@harbour-enterprises/superdoc 0.22.0-next.1 → 0.22.0-next.10
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-BpwMPbUj.es.js → PdfViewer-CJdQmuIm.es.js} +1 -1
- package/dist/chunks/{PdfViewer-B3KmcDup.cjs → PdfViewer-DE1NR4Ve.cjs} +1 -1
- package/dist/chunks/{index-Cw4YywoD.es.js → index-B9sHxXr_.es.js} +53 -26
- package/dist/chunks/{index-BOf6E2I4.cjs → index-nfoifSpX.cjs} +53 -26
- package/dist/chunks/{super-editor.es-DHDx2fsy.cjs → super-editor.es-DAP-fnHo.cjs} +2264 -1648
- package/dist/chunks/{super-editor.es-vfoWxyZL.es.js → super-editor.es-_iVPQ8J8.es.js} +2264 -1648
- package/dist/core/SuperDoc.d.ts +5 -0
- package/dist/core/SuperDoc.d.ts.map +1 -1
- package/dist/core/types/index.d.ts +4 -4
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/stores/comments-store.d.ts +4 -1
- package/dist/stores/comments-store.d.ts.map +1 -1
- package/dist/style.css +48 -44
- package/dist/super-editor/ai-writer.es.js +2 -2
- package/dist/super-editor/chunks/{converter-BcqEfCTg.js → converter-DK1NMJZB.js} +439 -169
- package/dist/super-editor/chunks/{docx-zipper-DZ9ph0iQ.js → docx-zipper-CmK8TyNb.js} +73 -12
- package/dist/super-editor/chunks/{editor-BC2sSIVa.js → editor-YR4uV-dp.js} +1902 -1607
- package/dist/super-editor/chunks/{toolbar-DNTo5DDf.js → toolbar-DzJyRvb0.js} +2 -2
- package/dist/super-editor/converter.es.js +1 -1
- package/dist/super-editor/docx-zipper.es.js +2 -2
- package/dist/super-editor/editor.es.js +3 -3
- package/dist/super-editor/file-zipper.es.js +1 -1
- package/dist/super-editor/src/core/DocxZipper.d.ts +1 -1
- package/dist/super-editor/src/core/super-converter/SuperConverter.d.ts +1 -13
- package/dist/super-editor/src/core/super-converter/exporter.d.ts +1 -0
- package/dist/super-editor/src/core/super-converter/helpers/tableFallbackHelpers.d.ts +24 -0
- package/dist/super-editor/src/extensions/custom-selection/custom-selection.d.ts +5 -1
- package/dist/super-editor/src/extensions/index.d.ts +2 -1
- package/dist/super-editor/src/extensions/structured-content/index.d.ts +1 -0
- package/dist/super-editor/src/extensions/structured-content/structured-content-commands.d.ts +67 -0
- package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentBlockTags.d.ts +7 -0
- package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentInlineTags.d.ts +7 -0
- package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentTags.d.ts +7 -0
- package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/getStructuredContentTagsById.d.ts +8 -0
- package/dist/super-editor/src/extensions/structured-content/structuredContentHelpers/index.d.ts +4 -0
- package/dist/super-editor/src/utils/contextmenu-helpers.d.ts +24 -0
- package/dist/super-editor/style.css +4 -0
- package/dist/super-editor/super-editor.es.js +8 -16
- package/dist/super-editor/toolbar.es.js +2 -2
- package/dist/super-editor.cjs +1 -1
- package/dist/super-editor.es.js +1 -1
- package/dist/superdoc.cjs +2 -2
- package/dist/superdoc.es.js +2 -2
- package/dist/superdoc.umd.js +1665 -1022
- package/dist/superdoc.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/super-editor/src/components/slash-menu/contextmenu-helpers.d.ts +0 -1
|
@@ -9,12 +9,12 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
9
9
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
10
10
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
11
11
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
12
|
-
var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, registerPluginByNameIfNotExists_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, initPagination_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn,
|
|
12
|
+
var _Attribute_static, getGlobalAttributes_fn, getNodeAndMarksAttributes_fn, _Schema_static, createNodesSchema_fn, createMarksSchema_fn, _events, _ExtensionService_instances, setupExtensions_fn, attachEditorEvents_fn, _editor, _stateValidators, _xmlValidators, _requiredNodeTypes, _requiredMarkTypes, _SuperValidator_instances, initializeValidators_fn, collectValidatorRequirements_fn, analyzeDocument_fn, _commandService, _Editor_instances, initContainerElement_fn, init_fn, initRichText_fn, onFocus_fn, checkHeadless_fn, registerCopyHandler_fn, insertNewFileData_fn, registerPluginByNameIfNotExists_fn, createExtensionService_fn, createCommandService_fn, createConverter_fn, initMedia_fn, initFonts_fn, createSchema_fn, generatePmData_fn, createView_fn, onCollaborationReady_fn, initComments_fn, initPagination_fn, dispatchTransaction_fn, handleNodeSelection_fn, prepareDocumentForImport_fn, prepareDocumentForExport_fn, endCollaboration_fn, validateDocumentInit_fn, validateDocumentExport_fn, initDevTools_fn, _DocumentSectionView_instances, init_fn2, addToolTip_fn, _ListItemNodeView_instances, init_fn3, _FieldAnnotationView_instances, createAnnotation_fn, _AutoPageNumberNodeView_instances, renderDom_fn, scheduleUpdateNodeStyle_fn;
|
|
13
13
|
import * as Y from "yjs";
|
|
14
14
|
import { UndoManager, Item as Item$1, ContentType, Text as Text$1, XmlElement, encodeStateAsUpdate } from "yjs";
|
|
15
|
-
import { P as PluginKey, a as Plugin, M as Mapping, N as NodeSelection, S as Selection, T as TextSelection, b as Slice, D as DOMSerializer, F as Fragment, c as DOMParser$1, d as Mark$1, e as dropPoint, A as AllSelection, p as process$1, B as Buffer2, f as callOrGet, g as getExtensionConfigField, h as getMarkType, i as getMarksFromSelection, j as getNodeType, k as getSchemaTypeNameByName, l as Schema$1, m as cleanSchemaItem, n as canSplit, o as defaultBlockAt$1, q as liftTarget, r as canJoin, s as joinPoint, t as replaceStep$1, R as ReplaceAroundStep$1, u as isTextSelection, v as getMarkRange, w as isMarkActive, x as isNodeActive, y as deleteProps, z as processContent, C as ReplaceStep, E as NodeRange, G as findWrapping, L as ListHelpers, H as findParentNode, I as isMacOS, J as isIOS, K as getSchemaTypeByName, O as inputRulesPlugin, Q as TrackDeleteMarkName, U as TrackInsertMarkName, V as v4, W as TrackFormatMarkName, X as comments_module_events, Y as findMark, Z as objectIncludes, _ as AddMarkStep, $ as RemoveMarkStep, a0 as twipsToLines, a1 as pixelsToTwips, a2 as helpers, a3 as posToDOMRect, a4 as CommandService, a5 as SuperConverter, a6 as createDocument, a7 as createDocFromMarkdown, a8 as createDocFromHTML, a9 as EditorState, aa as hasSomeParentWithClass, ab as isActive, ac as unflattenListsInHtml, ad as parseSizeUnit, ae as minMax, af as getLineHeightValueString, ag as
|
|
15
|
+
import { P as PluginKey, a as Plugin, M as Mapping, N as NodeSelection, S as Selection, T as TextSelection, b as Slice, D as DOMSerializer, F as Fragment, c as DOMParser$1, d as Mark$1, e as dropPoint, A as AllSelection, p as process$1, B as Buffer2, f as callOrGet, g as getExtensionConfigField, h as getMarkType, i as getMarksFromSelection, j as getNodeType, k as getSchemaTypeNameByName, l as Schema$1, m as cleanSchemaItem, n as canSplit, o as defaultBlockAt$1, q as liftTarget, r as canJoin, s as joinPoint, t as replaceStep$1, R as ReplaceAroundStep$1, u as isTextSelection, v as getMarkRange, w as isMarkActive, x as isNodeActive, y as deleteProps, z as processContent, C as ReplaceStep, E as NodeRange, G as findWrapping, L as ListHelpers, H as findParentNode, I as isMacOS, J as isIOS, K as getSchemaTypeByName, O as inputRulesPlugin, Q as TrackDeleteMarkName, U as TrackInsertMarkName, V as v4, W as TrackFormatMarkName, X as comments_module_events, Y as findMark, Z as objectIncludes, _ as AddMarkStep, $ as RemoveMarkStep, a0 as twipsToLines, a1 as pixelsToTwips, a2 as helpers, a3 as posToDOMRect, a4 as CommandService, a5 as SuperConverter, a6 as createDocument, a7 as createDocFromMarkdown, a8 as createDocFromHTML, a9 as EditorState, aa as hasSomeParentWithClass, ab as isActive, ac as unflattenListsInHtml, ad as parseSizeUnit, ae as minMax, af as getLineHeightValueString, ag as updateDOMAttributes, ah as findChildren$5, ai as htmlHandler, aj as InputRule, ak as kebabCase, al as findParentNodeClosestToPos, am as getListItemStyleDefinitions, an as docxNumberigHelpers, ao as parseIndentElement, ap as combineIndents, aq as SelectionRange, ar as Transform, as as isInTable$1, at as generateDocxRandomId, au as insertNewRelationship } from "./converter-DK1NMJZB.js";
|
|
16
16
|
import { ref, computed, createElementBlock, openBlock, withModifiers, Fragment as Fragment$1, renderList, normalizeClass, createCommentVNode, toDisplayString, createElementVNode, createApp } from "vue";
|
|
17
|
-
import { D as DocxZipper } from "./docx-zipper-
|
|
17
|
+
import { D as DocxZipper } from "./docx-zipper-CmK8TyNb.js";
|
|
18
18
|
var GOOD_LEAF_SIZE = 200;
|
|
19
19
|
var RopeSequence = function RopeSequence2() {
|
|
20
20
|
};
|
|
@@ -11675,9 +11675,11 @@ const toggleHeaderFooterEditMode = ({ editor, focusedSectionEditor, isEditMode,
|
|
|
11675
11675
|
item.editor.view.dom.setAttribute("documentmode", documentMode);
|
|
11676
11676
|
});
|
|
11677
11677
|
if (isEditMode) {
|
|
11678
|
-
const pm =
|
|
11679
|
-
pm
|
|
11680
|
-
|
|
11678
|
+
const pm = editor.view?.dom || editor.options.element?.querySelector?.(".ProseMirror");
|
|
11679
|
+
if (pm) {
|
|
11680
|
+
pm.classList.add("header-footer-edit");
|
|
11681
|
+
pm.setAttribute("aria-readonly", true);
|
|
11682
|
+
}
|
|
11681
11683
|
}
|
|
11682
11684
|
if (focusedSectionEditor) {
|
|
11683
11685
|
focusedSectionEditor.view.focus();
|
|
@@ -12105,28 +12107,25 @@ const handleTrackedChangeTransaction = (trackedChangeMeta, trackedChanges, newEd
|
|
|
12105
12107
|
if (emitParams) editor.emit("commentsUpdate", emitParams);
|
|
12106
12108
|
return newTrackedChanges;
|
|
12107
12109
|
};
|
|
12108
|
-
const getTrackedChangeText = ({ state,
|
|
12110
|
+
const getTrackedChangeText = ({ state, nodes, mark, marks, trackedChangeType, isDeletionInsertion }) => {
|
|
12109
12111
|
let trackedChangeText = "";
|
|
12110
12112
|
let deletionText = "";
|
|
12111
12113
|
if (trackedChangeType === TrackInsertMarkName) {
|
|
12112
|
-
trackedChangeText = node
|
|
12114
|
+
trackedChangeText = nodes.reduce((acc, node) => {
|
|
12115
|
+
if (!node.marks.find((nodeMark) => nodeMark.type.name === mark.type.name)) return acc;
|
|
12116
|
+
acc += node?.text || node?.textContent || "";
|
|
12117
|
+
return acc;
|
|
12118
|
+
}, "");
|
|
12113
12119
|
}
|
|
12114
12120
|
if (trackedChangeType === TrackFormatMarkName) {
|
|
12115
12121
|
trackedChangeText = translateFormatChangesToEnglish(mark.attrs);
|
|
12116
12122
|
}
|
|
12117
12123
|
if (trackedChangeType === TrackDeleteMarkName || isDeletionInsertion) {
|
|
12118
|
-
deletionText = node
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
const changeMarks = marks2.filter((mark2) => TRACK_CHANGE_MARKS.includes(mark2.type.name));
|
|
12124
|
-
if (!changeMarks.length) return false;
|
|
12125
|
-
const hasMatchingId = changeMarks.find((mark2) => mark2.attrs.id === id);
|
|
12126
|
-
if (hasMatchingId) return true;
|
|
12127
|
-
});
|
|
12128
|
-
deletionText = deletionNode?.node.text ?? "";
|
|
12129
|
-
}
|
|
12124
|
+
deletionText = nodes.reduce((acc, node) => {
|
|
12125
|
+
if (!node.marks.find((nodeMark) => nodeMark.type.name === TrackDeleteMarkName)) return acc;
|
|
12126
|
+
acc += node?.text || node?.textContent || "";
|
|
12127
|
+
return acc;
|
|
12128
|
+
}, "");
|
|
12130
12129
|
}
|
|
12131
12130
|
return {
|
|
12132
12131
|
deletionText,
|
|
@@ -12141,18 +12140,17 @@ const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes
|
|
|
12141
12140
|
const id = attrs.id;
|
|
12142
12141
|
const node = nodes[0];
|
|
12143
12142
|
const isDeletionInsertion = !!(marks.insertedMark && marks.deletionMark);
|
|
12144
|
-
let
|
|
12143
|
+
let nodesWithMark = [];
|
|
12145
12144
|
newEditorState.doc.descendants((node2) => {
|
|
12146
12145
|
const { marks: marks2 = [] } = node2;
|
|
12147
12146
|
const changeMarks = marks2.filter((mark) => TRACK_CHANGE_MARKS.includes(mark.type.name));
|
|
12148
12147
|
if (!changeMarks.length) return;
|
|
12149
12148
|
const hasMatchingId = changeMarks.find((mark) => mark.attrs.id === id);
|
|
12150
|
-
if (hasMatchingId)
|
|
12151
|
-
if (existingNode) return false;
|
|
12149
|
+
if (hasMatchingId) nodesWithMark.push(node2);
|
|
12152
12150
|
});
|
|
12153
12151
|
const { deletionText, trackedChangeText } = getTrackedChangeText({
|
|
12154
12152
|
state: newEditorState,
|
|
12155
|
-
|
|
12153
|
+
nodes: nodesWithMark.length ? nodesWithMark : [node],
|
|
12156
12154
|
mark: trackedMark,
|
|
12157
12155
|
marks,
|
|
12158
12156
|
trackedChangeType,
|
|
@@ -12182,14 +12180,6 @@ const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes
|
|
|
12182
12180
|
else if (event === "update") params2.event = comments_module_events.UPDATE;
|
|
12183
12181
|
return params2;
|
|
12184
12182
|
};
|
|
12185
|
-
function findNode$1(node, predicate) {
|
|
12186
|
-
let found = null;
|
|
12187
|
-
node.descendants((node2, pos) => {
|
|
12188
|
-
if (predicate(node2)) found = { node: node2, pos };
|
|
12189
|
-
if (found) return false;
|
|
12190
|
-
});
|
|
12191
|
-
return found;
|
|
12192
|
-
}
|
|
12193
12183
|
function findRangeById(doc2, id) {
|
|
12194
12184
|
let from2 = null, to = null;
|
|
12195
12185
|
doc2.descendants((node, pos) => {
|
|
@@ -12707,6 +12697,7 @@ const generateTableIfNecessary = ({ tableNode, annotationValues, tr, state }) =>
|
|
|
12707
12697
|
const mappedRowStart = tr.mapping.map(absoluteRowStart);
|
|
12708
12698
|
const rowEnd = mappedRowStart + rowNode.nodeSize;
|
|
12709
12699
|
tr.replaceWith(mappedRowStart, rowEnd, Fragment.from(newRows));
|
|
12700
|
+
tr.setMeta("tableGeneration", true);
|
|
12710
12701
|
} catch (error) {
|
|
12711
12702
|
console.error("Error during row generation:", error);
|
|
12712
12703
|
throw error;
|
|
@@ -13111,7 +13102,7 @@ function findFieldAnnotationsBetween(from2, to, doc2) {
|
|
|
13111
13102
|
}
|
|
13112
13103
|
function findRemovedFieldAnnotations(tr) {
|
|
13113
13104
|
let removedNodes = [];
|
|
13114
|
-
if (!tr.steps.length || tr.meta && !Object.keys(tr.meta).every((meta) => ["inputType", "uiEvent", "paste"].includes(meta)) || ["historyUndo", "historyRedo"].includes(tr.getMeta("inputType")) || ["drop"].includes(tr.getMeta("uiEvent")) || tr.getMeta("fieldAnnotationUpdate") === true) {
|
|
13105
|
+
if (!tr.steps.length || tr.meta && !Object.keys(tr.meta).every((meta) => ["inputType", "uiEvent", "paste"].includes(meta)) || ["historyUndo", "historyRedo"].includes(tr.getMeta("inputType")) || ["drop"].includes(tr.getMeta("uiEvent")) || tr.getMeta("fieldAnnotationUpdate") === true || tr.getMeta("tableGeneration") === true) {
|
|
13115
13106
|
return removedNodes;
|
|
13116
13107
|
}
|
|
13117
13108
|
const hasDeletion = transactionDeletedAnything(tr);
|
|
@@ -14332,7 +14323,7 @@ const _Editor = class _Editor extends EventEmitter {
|
|
|
14332
14323
|
setDocumentMode(documentMode) {
|
|
14333
14324
|
let cleanedMode = documentMode?.toLowerCase() || "editing";
|
|
14334
14325
|
if (!this.extensionService || !this.state) return;
|
|
14335
|
-
const pm =
|
|
14326
|
+
const pm = this.view?.dom || this.options.element?.querySelector?.(".ProseMirror");
|
|
14336
14327
|
if (this.options.role === "viewer") cleanedMode = "viewing";
|
|
14337
14328
|
if (this.options.role === "suggester" && cleanedMode === "editing") cleanedMode = "suggesting";
|
|
14338
14329
|
if (cleanedMode === "viewing") {
|
|
@@ -14820,7 +14811,8 @@ const _Editor = class _Editor extends EventEmitter {
|
|
|
14820
14811
|
files: this.options.content
|
|
14821
14812
|
},
|
|
14822
14813
|
media,
|
|
14823
|
-
true
|
|
14814
|
+
true,
|
|
14815
|
+
updatedDocs
|
|
14824
14816
|
);
|
|
14825
14817
|
return updatedDocs;
|
|
14826
14818
|
}
|
|
@@ -15380,9 +15372,11 @@ createView_fn = function(element) {
|
|
|
15380
15372
|
isEditMode: false,
|
|
15381
15373
|
documentMode: this.options.documentMode
|
|
15382
15374
|
});
|
|
15383
|
-
const pm =
|
|
15384
|
-
pm
|
|
15385
|
-
|
|
15375
|
+
const pm = this.view?.dom || this.options.element?.querySelector?.(".ProseMirror");
|
|
15376
|
+
if (pm) {
|
|
15377
|
+
pm.classList.remove("header-footer-edit");
|
|
15378
|
+
pm.setAttribute("aria-readonly", false);
|
|
15379
|
+
}
|
|
15386
15380
|
}
|
|
15387
15381
|
setWordSelection(view, pos);
|
|
15388
15382
|
}
|
|
@@ -16973,580 +16967,1590 @@ const SlashMenu = Extension.create({
|
|
|
16973
16967
|
return this.editor.options.isHeadless ? [] : [slashMenuPlugin];
|
|
16974
16968
|
}
|
|
16975
16969
|
});
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
16984
|
-
|
|
16985
|
-
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
16970
|
+
class StructuredContentViewBase {
|
|
16971
|
+
constructor(props) {
|
|
16972
|
+
__publicField(this, "node");
|
|
16973
|
+
__publicField(this, "view");
|
|
16974
|
+
__publicField(this, "getPos");
|
|
16975
|
+
__publicField(this, "decorations");
|
|
16976
|
+
__publicField(this, "innerDecorations");
|
|
16977
|
+
__publicField(this, "editor");
|
|
16978
|
+
__publicField(this, "extension");
|
|
16979
|
+
__publicField(this, "htmlAttributes");
|
|
16980
|
+
__publicField(this, "root");
|
|
16981
|
+
__publicField(this, "isDragging", false);
|
|
16982
|
+
this.node = props.node;
|
|
16983
|
+
this.view = props.editor.view;
|
|
16984
|
+
this.getPos = props.getPos;
|
|
16985
|
+
this.decorations = props.decorations;
|
|
16986
|
+
this.innerDecorations = props.innerDecorations;
|
|
16987
|
+
this.editor = props.editor;
|
|
16988
|
+
this.extension = props.extension;
|
|
16989
|
+
this.htmlAttributes = props.htmlAttributes;
|
|
16990
|
+
this.mount(props);
|
|
16991
|
+
}
|
|
16992
|
+
mount() {
|
|
16993
|
+
return;
|
|
16994
|
+
}
|
|
16995
|
+
get dom() {
|
|
16996
|
+
return this.root;
|
|
16997
|
+
}
|
|
16998
|
+
get contentDOM() {
|
|
16999
|
+
return null;
|
|
17000
|
+
}
|
|
17001
|
+
update(node, decorations, innerDecorations) {
|
|
17002
|
+
if (node.type !== this.node.type) {
|
|
17003
|
+
return false;
|
|
17004
|
+
}
|
|
17005
|
+
this.node = node;
|
|
17006
|
+
this.decorations = decorations;
|
|
17007
|
+
this.innerDecorations = innerDecorations;
|
|
17008
|
+
this.updateHTMLAttributes();
|
|
17009
|
+
return true;
|
|
17010
|
+
}
|
|
17011
|
+
stopEvent(event) {
|
|
17012
|
+
if (!this.dom) return false;
|
|
17013
|
+
const target = event.target;
|
|
17014
|
+
const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
|
|
17015
|
+
if (!isInElement) return false;
|
|
17016
|
+
const isDragEvent = event.type.startsWith("drag");
|
|
17017
|
+
const isDropEvent = event.type === "drop";
|
|
17018
|
+
const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
|
|
17019
|
+
if (isInput && !isDropEvent && !isDragEvent) return true;
|
|
17020
|
+
const { isEditable } = this.editor;
|
|
17021
|
+
const { isDragging } = this;
|
|
17022
|
+
const isDraggable = !!this.node.type.spec.draggable;
|
|
17023
|
+
const isSelectable = NodeSelection.isSelectable(this.node);
|
|
17024
|
+
const isCopyEvent = event.type === "copy";
|
|
17025
|
+
const isPasteEvent = event.type === "paste";
|
|
17026
|
+
const isCutEvent = event.type === "cut";
|
|
17027
|
+
const isClickEvent = event.type === "mousedown";
|
|
17028
|
+
if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
|
|
17029
|
+
event.preventDefault();
|
|
17030
|
+
}
|
|
17031
|
+
if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
|
|
17032
|
+
event.preventDefault();
|
|
17033
|
+
return false;
|
|
17034
|
+
}
|
|
17035
|
+
if (isDraggable && isEditable && !isDragging && isClickEvent) {
|
|
17036
|
+
const dragHandle = target.closest("[data-drag-handle]");
|
|
17037
|
+
const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
|
|
17038
|
+
if (isValidDragHandle) {
|
|
17039
|
+
this.isDragging = true;
|
|
17040
|
+
document.addEventListener(
|
|
17041
|
+
"dragend",
|
|
17042
|
+
() => {
|
|
17043
|
+
this.isDragging = false;
|
|
17044
|
+
},
|
|
17045
|
+
{ once: true }
|
|
17046
|
+
);
|
|
17047
|
+
document.addEventListener(
|
|
17048
|
+
"drop",
|
|
17049
|
+
() => {
|
|
17050
|
+
this.isDragging = false;
|
|
17051
|
+
},
|
|
17052
|
+
{ once: true }
|
|
17053
|
+
);
|
|
17054
|
+
document.addEventListener(
|
|
17055
|
+
"mouseup",
|
|
17056
|
+
() => {
|
|
17057
|
+
this.isDragging = false;
|
|
17058
|
+
},
|
|
17059
|
+
{ once: true }
|
|
17060
|
+
);
|
|
17025
17061
|
}
|
|
17026
|
-
}
|
|
17062
|
+
}
|
|
17063
|
+
if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
|
|
17064
|
+
return false;
|
|
17065
|
+
}
|
|
17066
|
+
return true;
|
|
17027
17067
|
}
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
return
|
|
17068
|
+
ignoreMutation(mutation) {
|
|
17069
|
+
if (!this.dom || !this.contentDOM) return true;
|
|
17070
|
+
if (this.node.isLeaf || this.node.isAtom) return true;
|
|
17071
|
+
if (mutation.type === "selection") return false;
|
|
17072
|
+
if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
|
|
17073
|
+
if (this.contentDOM.contains(mutation.target)) return false;
|
|
17074
|
+
return true;
|
|
17035
17075
|
}
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17076
|
+
destroy() {
|
|
17077
|
+
this.dom.remove();
|
|
17078
|
+
this.contentDOM?.remove();
|
|
17079
|
+
}
|
|
17080
|
+
updateAttributes(attrs) {
|
|
17081
|
+
const pos = this.getPos();
|
|
17082
|
+
if (typeof pos !== "number") {
|
|
17083
|
+
return;
|
|
17084
|
+
}
|
|
17085
|
+
return this.view.dispatch(
|
|
17086
|
+
this.view.state.tr.setNodeMarkup(pos, void 0, {
|
|
17087
|
+
...this.node.attrs,
|
|
17088
|
+
...attrs
|
|
17089
|
+
})
|
|
17090
|
+
);
|
|
17091
|
+
}
|
|
17092
|
+
updateHTMLAttributes() {
|
|
17093
|
+
const { extensionService } = this.editor;
|
|
17094
|
+
const { attributes } = extensionService;
|
|
17095
|
+
const extensionAttrs = attributes.filter((i) => i.type === this.node.type.name);
|
|
17096
|
+
this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
|
|
17097
|
+
}
|
|
17098
|
+
createDragHandle() {
|
|
17099
|
+
const dragHandle = document.createElement("span");
|
|
17100
|
+
dragHandle.classList.add("sd-structured-content-draggable");
|
|
17101
|
+
dragHandle.draggable = true;
|
|
17102
|
+
dragHandle.contentEditable = "false";
|
|
17103
|
+
dragHandle.dataset.dragHandle = "";
|
|
17104
|
+
const textElement = document.createElement("span");
|
|
17105
|
+
textElement.textContent = this.node.attrs.alias || "Structured content";
|
|
17106
|
+
dragHandle.append(textElement);
|
|
17107
|
+
return dragHandle;
|
|
17108
|
+
}
|
|
17109
|
+
onDragStart(event) {
|
|
17110
|
+
const { view } = this.editor;
|
|
17111
|
+
const target = event.target;
|
|
17112
|
+
const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
|
|
17113
|
+
if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
|
|
17114
|
+
return;
|
|
17115
|
+
}
|
|
17116
|
+
let x = 0;
|
|
17117
|
+
let y = 0;
|
|
17118
|
+
if (this.dom !== dragHandle) {
|
|
17119
|
+
const domBox = this.dom.getBoundingClientRect();
|
|
17120
|
+
const handleBox = dragHandle.getBoundingClientRect();
|
|
17121
|
+
const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
|
|
17122
|
+
const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
|
|
17123
|
+
x = handleBox.x - domBox.x + offsetX;
|
|
17124
|
+
y = handleBox.y - domBox.y + offsetY;
|
|
17125
|
+
}
|
|
17126
|
+
event.dataTransfer?.setDragImage(this.dom, x, y);
|
|
17127
|
+
const pos = this.getPos();
|
|
17128
|
+
if (typeof pos !== "number") {
|
|
17129
|
+
return;
|
|
17130
|
+
}
|
|
17131
|
+
const selection = NodeSelection.create(view.state.doc, pos);
|
|
17132
|
+
const transaction = view.state.tr.setSelection(selection);
|
|
17043
17133
|
view.dispatch(transaction);
|
|
17044
|
-
});
|
|
17045
|
-
if (handled) {
|
|
17046
|
-
tr.setMeta("preventDispatch", true);
|
|
17047
17134
|
}
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
17053
|
-
|
|
17135
|
+
}
|
|
17136
|
+
class StructuredContentInlineView extends StructuredContentViewBase {
|
|
17137
|
+
constructor(props) {
|
|
17138
|
+
super(props);
|
|
17139
|
+
}
|
|
17140
|
+
mount() {
|
|
17141
|
+
this.buildView();
|
|
17142
|
+
}
|
|
17143
|
+
get contentDOM() {
|
|
17144
|
+
const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
|
|
17145
|
+
return contentElement || null;
|
|
17146
|
+
}
|
|
17147
|
+
createElement() {
|
|
17148
|
+
const element = document.createElement("span");
|
|
17149
|
+
element.classList.add(structuredContentClass$1);
|
|
17150
|
+
element.setAttribute("data-structured-content", "");
|
|
17151
|
+
const contentElement = document.createElement("span");
|
|
17152
|
+
contentElement.classList.add(structuredContentInnerClass$1);
|
|
17153
|
+
element.append(contentElement);
|
|
17154
|
+
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
17155
|
+
updateDOMAttributes(element, { ...domAttrs });
|
|
17156
|
+
return { element, contentElement };
|
|
17157
|
+
}
|
|
17158
|
+
buildView() {
|
|
17159
|
+
const { element } = this.createElement();
|
|
17160
|
+
const dragHandle = this.createDragHandle();
|
|
17161
|
+
element.prepend(dragHandle);
|
|
17162
|
+
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
17163
|
+
this.root = element;
|
|
17164
|
+
}
|
|
17165
|
+
updateView() {
|
|
17166
|
+
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
17167
|
+
updateDOMAttributes(this.dom, { ...domAttrs });
|
|
17168
|
+
}
|
|
17169
|
+
update(node, decorations, innerDecorations) {
|
|
17170
|
+
const result = super.update(node, decorations, innerDecorations);
|
|
17171
|
+
if (!result) return false;
|
|
17172
|
+
this.updateView();
|
|
17173
|
+
return true;
|
|
17174
|
+
}
|
|
17175
|
+
}
|
|
17176
|
+
const structuredContentClass$1 = "sd-structured-content";
|
|
17177
|
+
const structuredContentInnerClass$1 = "sd-structured-content__content";
|
|
17178
|
+
const StructuredContent = Node$1.create({
|
|
17179
|
+
name: "structuredContent",
|
|
17180
|
+
group: "inline structuredContent",
|
|
17054
17181
|
inline: true,
|
|
17055
17182
|
content: "inline*",
|
|
17056
|
-
|
|
17057
|
-
|
|
17183
|
+
isolating: true,
|
|
17184
|
+
atom: false,
|
|
17185
|
+
// false - has editable content.
|
|
17186
|
+
draggable: true,
|
|
17058
17187
|
addOptions() {
|
|
17059
17188
|
return {
|
|
17060
17189
|
htmlAttributes: {
|
|
17061
|
-
|
|
17190
|
+
class: structuredContentClass$1,
|
|
17191
|
+
"aria-label": "Structured content node"
|
|
17062
17192
|
}
|
|
17063
17193
|
};
|
|
17064
17194
|
},
|
|
17065
17195
|
addAttributes() {
|
|
17066
17196
|
return {
|
|
17067
|
-
|
|
17197
|
+
id: {
|
|
17068
17198
|
default: null,
|
|
17069
|
-
|
|
17070
|
-
|
|
17199
|
+
parseDOM: (elem) => elem.getAttribute("data-id"),
|
|
17200
|
+
renderDOM: (attrs) => {
|
|
17201
|
+
if (!attrs.id) return {};
|
|
17202
|
+
return { "data-id": attrs.id };
|
|
17203
|
+
}
|
|
17071
17204
|
},
|
|
17072
|
-
|
|
17205
|
+
tag: {
|
|
17073
17206
|
default: null,
|
|
17074
|
-
|
|
17075
|
-
|
|
17207
|
+
parseDOM: (elem) => elem.getAttribute("data-tag"),
|
|
17208
|
+
renderDOM: (attrs) => {
|
|
17209
|
+
if (!attrs.tag) return {};
|
|
17210
|
+
return { "data-tag": attrs.tag };
|
|
17211
|
+
}
|
|
17076
17212
|
},
|
|
17077
|
-
|
|
17213
|
+
alias: {
|
|
17078
17214
|
default: null,
|
|
17079
|
-
|
|
17080
|
-
|
|
17215
|
+
parseDOM: (elem) => elem.getAttribute("data-alias"),
|
|
17216
|
+
renderDOM: (attrs) => {
|
|
17217
|
+
if (!attrs.alias) return {};
|
|
17218
|
+
return { "data-alias": attrs.alias };
|
|
17219
|
+
}
|
|
17081
17220
|
},
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
rendered: false,
|
|
17085
|
-
keepOnSplit: true
|
|
17221
|
+
sdtPr: {
|
|
17222
|
+
rendered: false
|
|
17086
17223
|
}
|
|
17087
17224
|
};
|
|
17088
17225
|
},
|
|
17089
|
-
addCommands() {
|
|
17090
|
-
return {
|
|
17091
|
-
splitRun
|
|
17092
|
-
};
|
|
17093
|
-
},
|
|
17094
17226
|
parseDOM() {
|
|
17095
|
-
return [{ tag: "span[data-
|
|
17227
|
+
return [{ tag: "span[data-structured-content]" }];
|
|
17096
17228
|
},
|
|
17097
17229
|
renderDOM({ htmlAttributes }) {
|
|
17098
|
-
|
|
17099
|
-
|
|
17230
|
+
return [
|
|
17231
|
+
"span",
|
|
17232
|
+
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
|
|
17233
|
+
"data-structured-content": ""
|
|
17234
|
+
}),
|
|
17235
|
+
0
|
|
17236
|
+
];
|
|
17237
|
+
},
|
|
17238
|
+
addNodeView() {
|
|
17239
|
+
return (props) => {
|
|
17240
|
+
return new StructuredContentInlineView({ ...props });
|
|
17241
|
+
};
|
|
17100
17242
|
}
|
|
17101
17243
|
});
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
17108
|
-
|
|
17109
|
-
|
|
17244
|
+
class StructuredContentBlockView extends StructuredContentViewBase {
|
|
17245
|
+
constructor(props) {
|
|
17246
|
+
super(props);
|
|
17247
|
+
}
|
|
17248
|
+
mount() {
|
|
17249
|
+
this.buildView();
|
|
17250
|
+
}
|
|
17251
|
+
get contentDOM() {
|
|
17252
|
+
const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass}`);
|
|
17253
|
+
return contentElement || null;
|
|
17254
|
+
}
|
|
17255
|
+
createElement() {
|
|
17256
|
+
const element = document.createElement("div");
|
|
17257
|
+
element.classList.add(structuredContentClass);
|
|
17258
|
+
element.setAttribute("data-structured-content-block", "");
|
|
17259
|
+
const contentElement = document.createElement("div");
|
|
17260
|
+
contentElement.classList.add(structuredContentInnerClass);
|
|
17261
|
+
element.append(contentElement);
|
|
17262
|
+
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
17263
|
+
updateDOMAttributes(element, { ...domAttrs });
|
|
17264
|
+
return { element, contentElement };
|
|
17265
|
+
}
|
|
17266
|
+
buildView() {
|
|
17267
|
+
const { element } = this.createElement();
|
|
17268
|
+
const dragHandle = this.createDragHandle();
|
|
17269
|
+
element.prepend(dragHandle);
|
|
17270
|
+
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
17271
|
+
this.root = element;
|
|
17272
|
+
}
|
|
17273
|
+
updateView() {
|
|
17274
|
+
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
17275
|
+
updateDOMAttributes(this.dom, { ...domAttrs });
|
|
17276
|
+
}
|
|
17277
|
+
update(node, decorations, innerDecorations) {
|
|
17278
|
+
const result = super.update(node, decorations, innerDecorations);
|
|
17279
|
+
if (!result) return false;
|
|
17280
|
+
this.updateView();
|
|
17281
|
+
return true;
|
|
17282
|
+
}
|
|
17283
|
+
}
|
|
17284
|
+
const structuredContentClass = "sd-structured-content-block";
|
|
17285
|
+
const structuredContentInnerClass = "sd-structured-content-block__content";
|
|
17286
|
+
const StructuredContentBlock = Node$1.create({
|
|
17287
|
+
name: "structuredContentBlock",
|
|
17288
|
+
group: "block structuredContent",
|
|
17289
|
+
content: "block*",
|
|
17290
|
+
isolating: true,
|
|
17291
|
+
atom: false,
|
|
17292
|
+
// false - has editable content.
|
|
17293
|
+
draggable: true,
|
|
17110
17294
|
addOptions() {
|
|
17111
17295
|
return {
|
|
17112
|
-
itemTypeName: "listItem",
|
|
17113
17296
|
htmlAttributes: {
|
|
17114
|
-
|
|
17115
|
-
|
|
17116
|
-
|
|
17117
|
-
keepAttributes: false
|
|
17297
|
+
class: structuredContentClass,
|
|
17298
|
+
"aria-label": "Structured content block node"
|
|
17299
|
+
}
|
|
17118
17300
|
};
|
|
17119
17301
|
},
|
|
17120
|
-
parseDOM() {
|
|
17121
|
-
return [{ tag: "ul" }];
|
|
17122
|
-
},
|
|
17123
|
-
renderDOM({ htmlAttributes }) {
|
|
17124
|
-
const attributes = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
|
|
17125
|
-
return ["ul", attributes, 0];
|
|
17126
|
-
},
|
|
17127
17302
|
addAttributes() {
|
|
17128
17303
|
return {
|
|
17129
|
-
|
|
17130
|
-
default:
|
|
17131
|
-
|
|
17304
|
+
id: {
|
|
17305
|
+
default: null,
|
|
17306
|
+
parseDOM: (elem) => elem.getAttribute("data-id"),
|
|
17307
|
+
renderDOM: (attrs) => {
|
|
17308
|
+
if (!attrs.id) return {};
|
|
17309
|
+
return { "data-id": attrs.id };
|
|
17310
|
+
}
|
|
17132
17311
|
},
|
|
17133
|
-
|
|
17134
|
-
|
|
17312
|
+
tag: {
|
|
17313
|
+
default: null,
|
|
17314
|
+
parseDOM: (elem) => elem.getAttribute("data-tag"),
|
|
17315
|
+
renderDOM: (attrs) => {
|
|
17316
|
+
if (!attrs.tag) return {};
|
|
17317
|
+
return { "data-tag": attrs.tag };
|
|
17318
|
+
}
|
|
17135
17319
|
},
|
|
17136
|
-
|
|
17320
|
+
alias: {
|
|
17137
17321
|
default: null,
|
|
17138
|
-
|
|
17139
|
-
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
17322
|
+
parseDOM: (elem) => elem.getAttribute("data-alias"),
|
|
17140
17323
|
renderDOM: (attrs) => {
|
|
17141
|
-
|
|
17324
|
+
if (!attrs.alias) return {};
|
|
17325
|
+
return { "data-alias": attrs.alias };
|
|
17142
17326
|
}
|
|
17143
17327
|
},
|
|
17144
|
-
|
|
17145
|
-
rendered: false
|
|
17146
|
-
keepOnSplit: true
|
|
17328
|
+
sdtPr: {
|
|
17329
|
+
rendered: false
|
|
17147
17330
|
}
|
|
17148
17331
|
};
|
|
17149
17332
|
},
|
|
17333
|
+
parseDOM() {
|
|
17334
|
+
return [{ tag: "div[data-structured-content-block]" }];
|
|
17335
|
+
},
|
|
17336
|
+
renderDOM({ htmlAttributes }) {
|
|
17337
|
+
return [
|
|
17338
|
+
"div",
|
|
17339
|
+
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
|
|
17340
|
+
"data-structured-content-block": ""
|
|
17341
|
+
}),
|
|
17342
|
+
0
|
|
17343
|
+
];
|
|
17344
|
+
},
|
|
17345
|
+
addNodeView() {
|
|
17346
|
+
return (props) => {
|
|
17347
|
+
return new StructuredContentBlockView({ ...props });
|
|
17348
|
+
};
|
|
17349
|
+
}
|
|
17350
|
+
});
|
|
17351
|
+
function getStructuredContentTagsById(idOrIds, state) {
|
|
17352
|
+
const result = findChildren$5(state.doc, (node) => {
|
|
17353
|
+
const isStructuredContent = ["structuredContent", "structuredContentBlock"].includes(node.type.name);
|
|
17354
|
+
if (Array.isArray(idOrIds)) {
|
|
17355
|
+
return isStructuredContent && idOrIds.includes(node.attrs.id);
|
|
17356
|
+
} else {
|
|
17357
|
+
return isStructuredContent && node.attrs.id === idOrIds;
|
|
17358
|
+
}
|
|
17359
|
+
});
|
|
17360
|
+
return result;
|
|
17361
|
+
}
|
|
17362
|
+
function getStructuredContentTags(state) {
|
|
17363
|
+
const result = findChildren$5(state.doc, (node) => {
|
|
17364
|
+
return node.type.name === "structuredContent" || node.type.name === "structuredContentBlock";
|
|
17365
|
+
});
|
|
17366
|
+
return result;
|
|
17367
|
+
}
|
|
17368
|
+
function getStructuredContentInlineTags(state) {
|
|
17369
|
+
const result = findChildren$5(state.doc, (node) => node.type.name === "structuredContent");
|
|
17370
|
+
return result;
|
|
17371
|
+
}
|
|
17372
|
+
function getStructuredContentBlockTags(state) {
|
|
17373
|
+
const result = findChildren$5(state.doc, (node) => node.type.name === "structuredContentBlock");
|
|
17374
|
+
return result;
|
|
17375
|
+
}
|
|
17376
|
+
const structuredContentHelpers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
17377
|
+
__proto__: null,
|
|
17378
|
+
getStructuredContentBlockTags,
|
|
17379
|
+
getStructuredContentInlineTags,
|
|
17380
|
+
getStructuredContentTags,
|
|
17381
|
+
getStructuredContentTagsById
|
|
17382
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
17383
|
+
const STRUCTURED_CONTENT_NAMES = ["structuredContent", "structuredContentBlock"];
|
|
17384
|
+
const StructuredContentCommands = Extension.create({
|
|
17385
|
+
name: "structuredContentCommands",
|
|
17150
17386
|
addCommands() {
|
|
17151
17387
|
return {
|
|
17152
17388
|
/**
|
|
17153
|
-
*
|
|
17389
|
+
* Inserts a structured content inline at selection.
|
|
17154
17390
|
* @category Command
|
|
17155
|
-
* @
|
|
17156
|
-
* // Toggle bullet list on selected text
|
|
17157
|
-
* editor.commands.toggleBulletList()
|
|
17158
|
-
* @note Converts selected paragraphs to list items or removes list formatting
|
|
17391
|
+
* @param {StructuredContentInlineInsert} options
|
|
17159
17392
|
*/
|
|
17160
|
-
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
|
|
17166
|
-
|
|
17167
|
-
|
|
17168
|
-
return this.editor.commands.toggleBulletList();
|
|
17169
|
-
}
|
|
17170
|
-
};
|
|
17171
|
-
},
|
|
17172
|
-
addInputRules() {
|
|
17173
|
-
return [
|
|
17174
|
-
new InputRule({
|
|
17175
|
-
match: inputRegex$1,
|
|
17176
|
-
handler: ({ state, range }) => {
|
|
17177
|
-
const $pos = state.selection.$from;
|
|
17178
|
-
const listItemType = state.schema.nodes.listItem;
|
|
17179
|
-
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
17180
|
-
if ($pos.node(depth).type === listItemType) {
|
|
17181
|
-
return null;
|
|
17182
|
-
}
|
|
17393
|
+
insertStructuredContentInline: (options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
17394
|
+
const { schema } = editor;
|
|
17395
|
+
let { from: from2, to } = state.selection;
|
|
17396
|
+
if (dispatch) {
|
|
17397
|
+
const selectionText = state.doc.textBetween(from2, to);
|
|
17398
|
+
let content = null;
|
|
17399
|
+
if (selectionText) {
|
|
17400
|
+
content = schema.text(selectionText);
|
|
17183
17401
|
}
|
|
17184
|
-
|
|
17185
|
-
|
|
17186
|
-
|
|
17187
|
-
|
|
17188
|
-
|
|
17189
|
-
|
|
17190
|
-
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
name: "orderedList",
|
|
17199
|
-
group: "block list",
|
|
17200
|
-
selectable: false,
|
|
17201
|
-
content() {
|
|
17202
|
-
return `${this.options.itemTypeName}+`;
|
|
17203
|
-
},
|
|
17204
|
-
addOptions() {
|
|
17205
|
-
return {
|
|
17206
|
-
itemTypeName: "listItem",
|
|
17207
|
-
htmlAttributes: {
|
|
17208
|
-
"aria-label": "Ordered list node"
|
|
17209
|
-
},
|
|
17210
|
-
keepMarks: true,
|
|
17211
|
-
keepAttributes: false,
|
|
17212
|
-
listStyleTypes: ["decimal", "lowerAlpha", "lowerRoman"]
|
|
17213
|
-
};
|
|
17214
|
-
},
|
|
17215
|
-
addAttributes() {
|
|
17216
|
-
return {
|
|
17217
|
-
order: {
|
|
17218
|
-
default: 1,
|
|
17219
|
-
parseDOM: (element) => {
|
|
17220
|
-
return element.hasAttribute("start") ? parseInt(element.getAttribute("start") || "", 10) : 1;
|
|
17221
|
-
},
|
|
17222
|
-
renderDOM: (attrs) => {
|
|
17223
|
-
return {
|
|
17224
|
-
start: attrs.order
|
|
17402
|
+
if (options.text) {
|
|
17403
|
+
content = schema.text(options.text);
|
|
17404
|
+
}
|
|
17405
|
+
if (options.json) {
|
|
17406
|
+
content = schema.nodeFromJSON(options.json);
|
|
17407
|
+
}
|
|
17408
|
+
if (!content) {
|
|
17409
|
+
content = schema.text(" ");
|
|
17410
|
+
}
|
|
17411
|
+
const attrs = {
|
|
17412
|
+
...options.attrs,
|
|
17413
|
+
id: options.attrs?.id || randomId(),
|
|
17414
|
+
tag: "inline_text_sdt",
|
|
17415
|
+
alias: options.attrs?.alias || "Structured content"
|
|
17225
17416
|
};
|
|
17417
|
+
const node = schema.nodes.structuredContent.create(attrs, content, null);
|
|
17418
|
+
const parent = findParentNode((node2) => node2.type.name === "structuredContent")(state.selection);
|
|
17419
|
+
if (parent) {
|
|
17420
|
+
const insertPos = parent.pos + parent.node.nodeSize;
|
|
17421
|
+
from2 = to = insertPos;
|
|
17422
|
+
}
|
|
17423
|
+
tr.replaceWith(from2, to, node);
|
|
17226
17424
|
}
|
|
17425
|
+
return true;
|
|
17227
17426
|
},
|
|
17228
|
-
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
17234
|
-
}
|
|
17235
|
-
|
|
17236
|
-
|
|
17237
|
-
|
|
17238
|
-
|
|
17239
|
-
|
|
17240
|
-
|
|
17241
|
-
|
|
17242
|
-
|
|
17427
|
+
/**
|
|
17428
|
+
* Inserts a structured content block at selection.
|
|
17429
|
+
* @category Command
|
|
17430
|
+
* @param {StructuredContentBlockInsert} options
|
|
17431
|
+
*/
|
|
17432
|
+
insertStructuredContentBlock: (options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
17433
|
+
const { schema } = editor;
|
|
17434
|
+
let { from: from2, to } = state.selection;
|
|
17435
|
+
if (dispatch) {
|
|
17436
|
+
const selectionContent = state.selection.content();
|
|
17437
|
+
let content = null;
|
|
17438
|
+
if (selectionContent.size) {
|
|
17439
|
+
content = selectionContent.content;
|
|
17440
|
+
}
|
|
17441
|
+
if (options.html) {
|
|
17442
|
+
const html = htmlHandler(options.html, editor);
|
|
17443
|
+
const doc2 = DOMParser$1.fromSchema(schema).parse(html);
|
|
17444
|
+
content = doc2.content;
|
|
17445
|
+
}
|
|
17446
|
+
if (options.json) {
|
|
17447
|
+
content = schema.nodeFromJSON(options.json);
|
|
17448
|
+
}
|
|
17449
|
+
if (!content) {
|
|
17450
|
+
content = schema.nodeFromJSON({ type: "paragraph", content: [] });
|
|
17451
|
+
}
|
|
17452
|
+
const attrs = {
|
|
17453
|
+
...options.attrs,
|
|
17454
|
+
id: options.attrs?.id || randomId(),
|
|
17455
|
+
tag: "block_table_sdt",
|
|
17456
|
+
alias: options.attrs?.alias || "Structured content"
|
|
17243
17457
|
};
|
|
17458
|
+
const node = schema.nodes.structuredContentBlock.create(attrs, content, null);
|
|
17459
|
+
const parent = findParentNode((node2) => node2.type.name === "structuredContentBlock")(state.selection);
|
|
17460
|
+
if (parent) {
|
|
17461
|
+
const insertPos = parent.pos + parent.node.nodeSize;
|
|
17462
|
+
from2 = to = insertPos;
|
|
17463
|
+
}
|
|
17464
|
+
tr.replaceRangeWith(from2, to, node);
|
|
17244
17465
|
}
|
|
17245
|
-
|
|
17466
|
+
return true;
|
|
17246
17467
|
},
|
|
17247
|
-
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
|
|
17251
|
-
|
|
17252
|
-
|
|
17253
|
-
|
|
17254
|
-
|
|
17468
|
+
/**
|
|
17469
|
+
* Updates a structured content attributes or content.
|
|
17470
|
+
* If the updated node does not match the schema, it will not be updated.
|
|
17471
|
+
* @category Command
|
|
17472
|
+
* @param {string} id
|
|
17473
|
+
* @param {StructuredContentUpdate} options
|
|
17474
|
+
*/
|
|
17475
|
+
updateStructuredContentById: (id, options = {}) => ({ editor, dispatch, state, tr }) => {
|
|
17476
|
+
const structuredContentTags = getStructuredContentTagsById(id, state);
|
|
17477
|
+
if (!structuredContentTags.length) {
|
|
17478
|
+
return true;
|
|
17255
17479
|
}
|
|
17480
|
+
const { schema } = editor;
|
|
17481
|
+
if (dispatch) {
|
|
17482
|
+
const structuredContent = structuredContentTags[0];
|
|
17483
|
+
const { pos, node } = structuredContent;
|
|
17484
|
+
const posFrom = pos;
|
|
17485
|
+
const posTo = pos + node.nodeSize;
|
|
17486
|
+
let content = null;
|
|
17487
|
+
if (options.text) {
|
|
17488
|
+
content = schema.text(options.text);
|
|
17489
|
+
}
|
|
17490
|
+
if (options.html) {
|
|
17491
|
+
const html = htmlHandler(options.html, editor);
|
|
17492
|
+
const doc2 = DOMParser$1.fromSchema(schema).parse(html);
|
|
17493
|
+
content = doc2.content;
|
|
17494
|
+
}
|
|
17495
|
+
if (options.json) {
|
|
17496
|
+
content = schema.nodeFromJSON(options.json);
|
|
17497
|
+
}
|
|
17498
|
+
if (!content) {
|
|
17499
|
+
content = node.content;
|
|
17500
|
+
}
|
|
17501
|
+
const updatedNode = node.type.create({ ...node.attrs, ...options.attrs }, content, node.marks);
|
|
17502
|
+
try {
|
|
17503
|
+
updatedNode.check();
|
|
17504
|
+
} catch {
|
|
17505
|
+
console.error("Updated node does not conform to the schema");
|
|
17506
|
+
return false;
|
|
17507
|
+
}
|
|
17508
|
+
tr.replaceWith(posFrom, posTo, updatedNode);
|
|
17509
|
+
}
|
|
17510
|
+
return true;
|
|
17256
17511
|
},
|
|
17257
|
-
"list-style-type": {
|
|
17258
|
-
default: "decimal",
|
|
17259
|
-
rendered: false
|
|
17260
|
-
},
|
|
17261
|
-
attributes: {
|
|
17262
|
-
rendered: false,
|
|
17263
|
-
keepOnSplit: true
|
|
17264
|
-
}
|
|
17265
|
-
};
|
|
17266
|
-
},
|
|
17267
|
-
parseDOM() {
|
|
17268
|
-
return [{ tag: "ol" }];
|
|
17269
|
-
},
|
|
17270
|
-
renderDOM({ htmlAttributes }) {
|
|
17271
|
-
const { start: start2, ...restAttributes } = htmlAttributes;
|
|
17272
|
-
return start2 === 1 ? ["ol", Attribute.mergeAttributes(this.options.htmlAttributes, restAttributes), 0] : ["ol", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
17273
|
-
},
|
|
17274
|
-
addCommands() {
|
|
17275
|
-
return {
|
|
17276
17512
|
/**
|
|
17277
|
-
*
|
|
17513
|
+
* Removes a structured content.
|
|
17278
17514
|
* @category Command
|
|
17279
|
-
* @
|
|
17280
|
-
* editor.commands.toggleOrderedList()
|
|
17281
|
-
* @note Converts selection to ordered list or back to paragraphs
|
|
17515
|
+
* @param {Array<{ node: Node, pos: number }>} structuredContentTags
|
|
17282
17516
|
*/
|
|
17283
|
-
|
|
17284
|
-
|
|
17517
|
+
deleteStructuredContent: (structuredContentTags) => ({ dispatch, tr }) => {
|
|
17518
|
+
if (!structuredContentTags.length) {
|
|
17519
|
+
return true;
|
|
17520
|
+
}
|
|
17521
|
+
if (dispatch) {
|
|
17522
|
+
structuredContentTags.forEach((structuredContent) => {
|
|
17523
|
+
const { pos, node } = structuredContent;
|
|
17524
|
+
const posFrom = tr.mapping.map(pos);
|
|
17525
|
+
const posTo = tr.mapping.map(pos + node.nodeSize);
|
|
17526
|
+
const currentNode = tr.doc.nodeAt(posFrom);
|
|
17527
|
+
if (currentNode && node.eq(currentNode)) {
|
|
17528
|
+
tr.delete(posFrom, posTo);
|
|
17529
|
+
}
|
|
17530
|
+
});
|
|
17531
|
+
}
|
|
17532
|
+
return true;
|
|
17285
17533
|
},
|
|
17286
17534
|
/**
|
|
17287
|
-
*
|
|
17535
|
+
* Removes a structured content by ID.
|
|
17288
17536
|
* @category Command
|
|
17289
|
-
* @param {
|
|
17290
|
-
* @param {number} pos - Starting position
|
|
17291
|
-
* @example
|
|
17292
|
-
* editor.commands.restartListNodes(nodes, position)
|
|
17293
|
-
* @note Resets list numbering for specified nodes
|
|
17537
|
+
* @param {string | string[]} idOrIds
|
|
17294
17538
|
*/
|
|
17295
|
-
|
|
17296
|
-
|
|
17297
|
-
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17539
|
+
deleteStructuredContentById: (idOrIds) => ({ dispatch, state, tr }) => {
|
|
17540
|
+
const structuredContentTags = getStructuredContentTagsById(idOrIds, state);
|
|
17541
|
+
if (!structuredContentTags.length) {
|
|
17542
|
+
return true;
|
|
17543
|
+
}
|
|
17544
|
+
if (dispatch) {
|
|
17545
|
+
structuredContentTags.forEach((structuredContent) => {
|
|
17546
|
+
const { pos, node } = structuredContent;
|
|
17547
|
+
const posFrom = tr.mapping.map(pos);
|
|
17548
|
+
const posTo = tr.mapping.map(pos + node.nodeSize);
|
|
17549
|
+
const currentNode = tr.doc.nodeAt(posFrom);
|
|
17550
|
+
if (currentNode && node.eq(currentNode)) {
|
|
17551
|
+
tr.delete(posFrom, posTo);
|
|
17552
|
+
}
|
|
17553
|
+
});
|
|
17554
|
+
}
|
|
17310
17555
|
return true;
|
|
17311
17556
|
},
|
|
17312
17557
|
/**
|
|
17313
|
-
*
|
|
17558
|
+
* Removes a structured content at cursor, preserving its content.
|
|
17314
17559
|
* @category Command
|
|
17315
|
-
* @example
|
|
17316
|
-
* editor.commands.updateOrderedListStyleType()
|
|
17317
|
-
* @note Cycles through decimal -> lowerAlpha -> lowerRoman based on depth
|
|
17318
17560
|
*/
|
|
17319
|
-
|
|
17320
|
-
|
|
17321
|
-
|
|
17561
|
+
deleteStructuredContentAtSelection: () => ({ editor, dispatch, state, tr }) => {
|
|
17562
|
+
const predicate = (node) => STRUCTURED_CONTENT_NAMES.includes(node.type.name);
|
|
17563
|
+
const structuredContent = findParentNode(predicate)(state.selection);
|
|
17564
|
+
if (!structuredContent) {
|
|
17322
17565
|
return true;
|
|
17323
17566
|
}
|
|
17324
17567
|
if (dispatch) {
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
17329
|
-
|
|
17330
|
-
if (currentListStyle !== listStyle && nodeAtPos.eq(list.node)) {
|
|
17331
|
-
tr.setNodeMarkup(list.pos, void 0, {
|
|
17332
|
-
...list.node.attrs,
|
|
17333
|
-
...{
|
|
17334
|
-
"list-style-type": listStyle
|
|
17335
|
-
}
|
|
17336
|
-
});
|
|
17337
|
-
}
|
|
17568
|
+
const { node, pos } = structuredContent;
|
|
17569
|
+
const posFrom = pos;
|
|
17570
|
+
const posTo = posFrom + node.nodeSize;
|
|
17571
|
+
const content = node.content;
|
|
17572
|
+
tr.replaceWith(posFrom, posTo, content);
|
|
17338
17573
|
}
|
|
17339
17574
|
return true;
|
|
17340
17575
|
}
|
|
17341
17576
|
};
|
|
17342
17577
|
},
|
|
17343
|
-
|
|
17578
|
+
addHelpers() {
|
|
17344
17579
|
return {
|
|
17345
|
-
|
|
17346
|
-
return this.editor.commands.toggleOrderedList();
|
|
17347
|
-
}
|
|
17580
|
+
...structuredContentHelpers
|
|
17348
17581
|
};
|
|
17349
|
-
},
|
|
17350
|
-
addInputRules() {
|
|
17351
|
-
return [
|
|
17352
|
-
new InputRule({
|
|
17353
|
-
match: inputRegex,
|
|
17354
|
-
handler: ({ state, range }) => {
|
|
17355
|
-
const $pos = state.selection.$from;
|
|
17356
|
-
const listItemType = state.schema.nodes.listItem;
|
|
17357
|
-
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
17358
|
-
if ($pos.node(depth).type === listItemType) {
|
|
17359
|
-
return null;
|
|
17360
|
-
}
|
|
17361
|
-
}
|
|
17362
|
-
const { tr } = state;
|
|
17363
|
-
tr.delete(range.from, range.to);
|
|
17364
|
-
ListHelpers.createNewList({
|
|
17365
|
-
listType: this.type,
|
|
17366
|
-
tr,
|
|
17367
|
-
editor: this.editor
|
|
17368
|
-
});
|
|
17369
|
-
}
|
|
17370
|
-
})
|
|
17371
|
-
];
|
|
17372
17582
|
}
|
|
17373
17583
|
});
|
|
17374
|
-
const
|
|
17375
|
-
|
|
17376
|
-
return handler ? handler(listLevel, lvlText, customFormat) : null;
|
|
17377
|
-
};
|
|
17378
|
-
const handleDecimal = (path, lvlText) => generateNumbering(path, lvlText, String);
|
|
17379
|
-
const handleRoman = (path, lvlText) => generateNumbering(path, lvlText, intToRoman);
|
|
17380
|
-
const handleLowerRoman = (path, lvlText) => handleRoman(path, lvlText).toLowerCase();
|
|
17381
|
-
const handleLowerAlpha = (path, lvlText) => handleAlpha(path, lvlText).toLowerCase();
|
|
17382
|
-
const handleAlpha = (path, lvlText) => generateNumbering(path, lvlText, (p) => intToAlpha(p));
|
|
17383
|
-
const handleOrdinal = (path, lvlText) => generateNumbering(path, lvlText, ordinalFormatter);
|
|
17384
|
-
const handleCustom = (path, lvlText, customFormat) => generateFromCustom(path, lvlText, customFormat);
|
|
17385
|
-
const handleJapaneseCounting = (path, lvlText) => generateNumbering(path, lvlText, intToJapaneseCounting);
|
|
17386
|
-
const listIndexMap = {
|
|
17387
|
-
decimal: handleDecimal,
|
|
17388
|
-
lowerRoman: handleLowerRoman,
|
|
17389
|
-
upperRoman: handleRoman,
|
|
17390
|
-
lowerLetter: handleLowerAlpha,
|
|
17391
|
-
upperLetter: handleAlpha,
|
|
17392
|
-
ordinal: handleOrdinal,
|
|
17393
|
-
custom: handleCustom,
|
|
17394
|
-
japaneseCounting: handleJapaneseCounting
|
|
17395
|
-
};
|
|
17396
|
-
const createNumbering = (values, lvlText) => {
|
|
17397
|
-
return values.reduce((acc, value, index2) => {
|
|
17398
|
-
return value > 9 ? acc.replace(/^0/, "").replace(`%${index2 + 1}`, value) : acc.replace(`%${index2 + 1}`, value);
|
|
17399
|
-
}, lvlText);
|
|
17584
|
+
const randomId = () => {
|
|
17585
|
+
return Math.floor(Math.random() * 4294967295).toString();
|
|
17400
17586
|
};
|
|
17401
|
-
|
|
17402
|
-
|
|
17403
|
-
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
return p;
|
|
17411
|
-
};
|
|
17412
|
-
const generateFromCustom = (path, lvlText, customFormat) => {
|
|
17413
|
-
if (customFormat !== "001, 002, 003, ...") return generateNumbering(path, lvlText, String);
|
|
17414
|
-
const match = customFormat.match(/(\d+)/);
|
|
17415
|
-
if (!match) throw new Error("Invalid format string: no numeric pattern found");
|
|
17416
|
-
const sample = match[1];
|
|
17417
|
-
const digitCount = sample.length;
|
|
17418
|
-
const index2 = path.pop();
|
|
17419
|
-
return String(index2).padStart(digitCount, "0");
|
|
17420
|
-
};
|
|
17421
|
-
const intToRoman = (num) => {
|
|
17422
|
-
const romanNumeralMap = [
|
|
17423
|
-
{ value: 1e3, numeral: "M" },
|
|
17424
|
-
{ value: 900, numeral: "CM" },
|
|
17425
|
-
{ value: 500, numeral: "D" },
|
|
17426
|
-
{ value: 400, numeral: "CD" },
|
|
17427
|
-
{ value: 100, numeral: "C" },
|
|
17428
|
-
{ value: 90, numeral: "XC" },
|
|
17429
|
-
{ value: 50, numeral: "L" },
|
|
17430
|
-
{ value: 40, numeral: "XL" },
|
|
17431
|
-
{ value: 10, numeral: "X" },
|
|
17432
|
-
{ value: 9, numeral: "IX" },
|
|
17433
|
-
{ value: 5, numeral: "V" },
|
|
17434
|
-
{ value: 4, numeral: "IV" },
|
|
17435
|
-
{ value: 1, numeral: "I" }
|
|
17436
|
-
];
|
|
17437
|
-
let result = "";
|
|
17438
|
-
for (const { value, numeral } of romanNumeralMap) {
|
|
17439
|
-
while (num >= value) {
|
|
17440
|
-
result += numeral;
|
|
17441
|
-
num -= value;
|
|
17442
|
-
}
|
|
17587
|
+
class DocumentSectionView {
|
|
17588
|
+
constructor(node, getPos, decorations, editor) {
|
|
17589
|
+
__privateAdd(this, _DocumentSectionView_instances);
|
|
17590
|
+
this.node = node;
|
|
17591
|
+
this.editor = editor;
|
|
17592
|
+
this.decorations = decorations;
|
|
17593
|
+
this.view = editor.view;
|
|
17594
|
+
this.getPos = getPos;
|
|
17595
|
+
__privateMethod(this, _DocumentSectionView_instances, init_fn2).call(this);
|
|
17443
17596
|
}
|
|
17444
|
-
|
|
17597
|
+
}
|
|
17598
|
+
_DocumentSectionView_instances = new WeakSet();
|
|
17599
|
+
init_fn2 = function() {
|
|
17600
|
+
const { attrs } = this.node;
|
|
17601
|
+
const { id, title, description } = attrs;
|
|
17602
|
+
this.dom = document.createElement("div");
|
|
17603
|
+
this.dom.className = "sd-document-section-block";
|
|
17604
|
+
this.dom.setAttribute("data-id", id);
|
|
17605
|
+
this.dom.setAttribute("data-title", title);
|
|
17606
|
+
this.dom.setAttribute("data-description", description);
|
|
17607
|
+
this.dom.setAttribute("aria-label", "Document section");
|
|
17608
|
+
__privateMethod(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
|
|
17609
|
+
this.contentDOM = document.createElement("div");
|
|
17610
|
+
this.contentDOM.className = "sd-document-section-block-content";
|
|
17611
|
+
this.contentDOM.setAttribute("contenteditable", "true");
|
|
17612
|
+
this.dom.appendChild(this.contentDOM);
|
|
17445
17613
|
};
|
|
17446
|
-
|
|
17447
|
-
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
|
|
17451
|
-
|
|
17452
|
-
|
|
17453
|
-
|
|
17454
|
-
|
|
17614
|
+
addToolTip_fn = function() {
|
|
17615
|
+
const { title } = this.node.attrs;
|
|
17616
|
+
this.infoDiv = document.createElement("div");
|
|
17617
|
+
this.infoDiv.className = "sd-document-section-block-info";
|
|
17618
|
+
const textSpan = document.createElement("span");
|
|
17619
|
+
textSpan.textContent = title || "Document section";
|
|
17620
|
+
this.infoDiv.appendChild(textSpan);
|
|
17621
|
+
this.infoDiv.setAttribute("contenteditable", "false");
|
|
17622
|
+
this.dom.appendChild(this.infoDiv);
|
|
17455
17623
|
};
|
|
17456
|
-
const
|
|
17457
|
-
|
|
17458
|
-
const
|
|
17459
|
-
if (
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
|
|
17464
|
-
|
|
17465
|
-
const digit = tempNum % 10;
|
|
17466
|
-
if (digit !== 0) {
|
|
17467
|
-
const digitStr = digit === 1 && unitIndex > 0 ? "" : digits[digit];
|
|
17468
|
-
result = digitStr + (unitIndex > 0 ? units[unitIndex] : "") + result;
|
|
17469
|
-
} else if (result && tempNum > 0) {
|
|
17470
|
-
if (!result.startsWith("零") && tempNum % 100 !== 0) {
|
|
17471
|
-
result = "零" + result;
|
|
17472
|
-
}
|
|
17624
|
+
const getAllSections = (editor) => {
|
|
17625
|
+
if (!editor) return [];
|
|
17626
|
+
const type = editor.schema.nodes.documentSection;
|
|
17627
|
+
if (!type) return [];
|
|
17628
|
+
const sections = [];
|
|
17629
|
+
const { state } = editor;
|
|
17630
|
+
state.doc.descendants((node, pos) => {
|
|
17631
|
+
if (node.type.name === type.name) {
|
|
17632
|
+
sections.push({ node, pos });
|
|
17473
17633
|
}
|
|
17474
|
-
|
|
17475
|
-
|
|
17476
|
-
|
|
17477
|
-
|
|
17478
|
-
|
|
17479
|
-
|
|
17480
|
-
|
|
17634
|
+
});
|
|
17635
|
+
return sections;
|
|
17636
|
+
};
|
|
17637
|
+
const exportSectionsToHTML = (editor) => {
|
|
17638
|
+
const sections = getAllSections(editor);
|
|
17639
|
+
const processedSections = /* @__PURE__ */ new Set();
|
|
17640
|
+
const result = [];
|
|
17641
|
+
sections.forEach(({ node }) => {
|
|
17642
|
+
const { attrs } = node;
|
|
17643
|
+
const { id, title, description } = attrs;
|
|
17644
|
+
if (processedSections.has(id)) return;
|
|
17645
|
+
processedSections.add(id);
|
|
17646
|
+
const html = getHTMLFromNode(node, editor);
|
|
17647
|
+
result.push({
|
|
17648
|
+
id,
|
|
17649
|
+
title,
|
|
17650
|
+
description,
|
|
17651
|
+
html
|
|
17652
|
+
});
|
|
17653
|
+
});
|
|
17481
17654
|
return result;
|
|
17482
17655
|
};
|
|
17483
|
-
const
|
|
17484
|
-
const
|
|
17485
|
-
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
return Boolean(isKeyboardInvocation);
|
|
17656
|
+
const getHTMLFromNode = (node, editor) => {
|
|
17657
|
+
const tempDocument = document.implementation.createHTMLDocument();
|
|
17658
|
+
const container = tempDocument.createElement("div");
|
|
17659
|
+
const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
|
|
17660
|
+
container.appendChild(fragment);
|
|
17661
|
+
let html = container.innerHTML;
|
|
17662
|
+
return html;
|
|
17491
17663
|
};
|
|
17492
|
-
const
|
|
17493
|
-
const
|
|
17494
|
-
|
|
17495
|
-
const
|
|
17496
|
-
|
|
17497
|
-
|
|
17498
|
-
|
|
17499
|
-
|
|
17500
|
-
|
|
17501
|
-
|
|
17502
|
-
|
|
17664
|
+
const exportSectionsToJSON = (editor) => {
|
|
17665
|
+
const sections = getAllSections(editor);
|
|
17666
|
+
const processedSections = /* @__PURE__ */ new Set();
|
|
17667
|
+
const result = [];
|
|
17668
|
+
sections.forEach(({ node }) => {
|
|
17669
|
+
const { attrs } = node;
|
|
17670
|
+
const { id, title, description } = attrs;
|
|
17671
|
+
if (processedSections.has(id)) return;
|
|
17672
|
+
processedSections.add(id);
|
|
17673
|
+
result.push({
|
|
17674
|
+
id,
|
|
17675
|
+
title,
|
|
17676
|
+
description,
|
|
17677
|
+
content: node.toJSON()
|
|
17503
17678
|
});
|
|
17504
|
-
}
|
|
17679
|
+
});
|
|
17680
|
+
return result;
|
|
17505
17681
|
};
|
|
17506
|
-
|
|
17507
|
-
|
|
17508
|
-
|
|
17509
|
-
|
|
17510
|
-
|
|
17511
|
-
|
|
17512
|
-
|
|
17513
|
-
|
|
17514
|
-
|
|
17515
|
-
const
|
|
17516
|
-
|
|
17682
|
+
const getLinkedSectionEditor = (id, options, editor) => {
|
|
17683
|
+
const sections = getAllSections(editor);
|
|
17684
|
+
const section = sections.find((s) => s.node.attrs.id === id);
|
|
17685
|
+
if (!section) return null;
|
|
17686
|
+
const child = editor.createChildEditor({
|
|
17687
|
+
...options,
|
|
17688
|
+
onUpdate: ({ editor: childEditor, transaction }) => {
|
|
17689
|
+
const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
|
|
17690
|
+
if (isFromtLinkedParent) return;
|
|
17691
|
+
const updatedContent = childEditor.state.doc.content;
|
|
17692
|
+
const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
|
|
17693
|
+
if (!sectionNode) return;
|
|
17694
|
+
const { pos, node } = sectionNode;
|
|
17695
|
+
const newNode = node.type.create(node.attrs, updatedContent, node.marks);
|
|
17696
|
+
const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
|
17697
|
+
tr.setMeta("fromLinkedChild", true);
|
|
17698
|
+
editor.view.dispatch(tr);
|
|
17699
|
+
}
|
|
17700
|
+
});
|
|
17701
|
+
editor.on("update", ({ transaction }) => {
|
|
17702
|
+
const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
|
|
17703
|
+
if (isFromLinkedChild) return;
|
|
17704
|
+
const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
|
|
17705
|
+
if (!sectionNode) return;
|
|
17706
|
+
const sectionContent = sectionNode.node.content;
|
|
17707
|
+
const json = {
|
|
17708
|
+
type: "doc",
|
|
17709
|
+
content: sectionContent.content.map((node) => node.toJSON())
|
|
17710
|
+
};
|
|
17711
|
+
const childTr = child.state.tr;
|
|
17712
|
+
childTr.setMeta("fromLinkedParent", true);
|
|
17713
|
+
childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
|
|
17714
|
+
child.view.dispatch(childTr);
|
|
17715
|
+
});
|
|
17716
|
+
return child;
|
|
17517
17717
|
};
|
|
17518
|
-
const
|
|
17519
|
-
|
|
17718
|
+
const SectionHelpers = {
|
|
17719
|
+
getAllSections,
|
|
17720
|
+
exportSectionsToHTML,
|
|
17721
|
+
exportSectionsToJSON,
|
|
17722
|
+
getLinkedSectionEditor
|
|
17520
17723
|
};
|
|
17521
|
-
const
|
|
17522
|
-
name: "
|
|
17523
|
-
|
|
17524
|
-
|
|
17525
|
-
|
|
17526
|
-
|
|
17527
|
-
|
|
17528
|
-
|
|
17529
|
-
|
|
17530
|
-
|
|
17531
|
-
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
|
|
17538
|
-
|
|
17724
|
+
const DocumentSection = Node$1.create({
|
|
17725
|
+
name: "documentSection",
|
|
17726
|
+
group: "block",
|
|
17727
|
+
content: "block*",
|
|
17728
|
+
atom: true,
|
|
17729
|
+
isolating: true,
|
|
17730
|
+
addOptions() {
|
|
17731
|
+
return {
|
|
17732
|
+
htmlAttributes: {
|
|
17733
|
+
class: "sd-document-section-block",
|
|
17734
|
+
"aria-label": "Structured content block"
|
|
17735
|
+
}
|
|
17736
|
+
};
|
|
17737
|
+
},
|
|
17738
|
+
parseDOM() {
|
|
17739
|
+
return [
|
|
17740
|
+
{
|
|
17741
|
+
tag: "div.sd-document-section-block",
|
|
17742
|
+
priority: 60
|
|
17743
|
+
}
|
|
17744
|
+
];
|
|
17745
|
+
},
|
|
17746
|
+
renderDOM({ htmlAttributes }) {
|
|
17747
|
+
return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
17748
|
+
},
|
|
17749
|
+
addAttributes() {
|
|
17750
|
+
return {
|
|
17751
|
+
id: {},
|
|
17752
|
+
sdBlockId: {
|
|
17753
|
+
default: null,
|
|
17754
|
+
keepOnSplit: false,
|
|
17755
|
+
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
17756
|
+
renderDOM: (attrs) => {
|
|
17757
|
+
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
17539
17758
|
}
|
|
17540
17759
|
},
|
|
17541
|
-
|
|
17542
|
-
|
|
17543
|
-
|
|
17544
|
-
|
|
17545
|
-
|
|
17546
|
-
|
|
17547
|
-
|
|
17548
|
-
|
|
17549
|
-
|
|
17760
|
+
title: {},
|
|
17761
|
+
description: {},
|
|
17762
|
+
sectionType: {},
|
|
17763
|
+
isLocked: { default: false }
|
|
17764
|
+
};
|
|
17765
|
+
},
|
|
17766
|
+
addNodeView() {
|
|
17767
|
+
return ({ node, editor, getPos, decorations }) => {
|
|
17768
|
+
return new DocumentSectionView(node, getPos, decorations, editor);
|
|
17769
|
+
};
|
|
17770
|
+
},
|
|
17771
|
+
addCommands() {
|
|
17772
|
+
return {
|
|
17773
|
+
/**
|
|
17774
|
+
* Create a lockable content section
|
|
17775
|
+
* @category Command
|
|
17776
|
+
* @param {SectionCreate} [options={}] - Section configuration
|
|
17777
|
+
* @example
|
|
17778
|
+
* editor.commands.createDocumentSection({
|
|
17779
|
+
* id: 1,
|
|
17780
|
+
* title: 'Terms & Conditions',
|
|
17781
|
+
* isLocked: true,
|
|
17782
|
+
* html: '<p>Legal content...</p>'
|
|
17783
|
+
* })
|
|
17784
|
+
*/
|
|
17785
|
+
createDocumentSection: (options = {}) => ({ tr, state, dispatch, editor }) => {
|
|
17786
|
+
const { selection } = state;
|
|
17787
|
+
let { from: from2, to } = selection;
|
|
17788
|
+
let content = selection.content().content;
|
|
17789
|
+
const { html: optionsHTML, json: optionsJSON } = options;
|
|
17790
|
+
if (optionsHTML) {
|
|
17791
|
+
const html = htmlHandler(optionsHTML, this.editor);
|
|
17792
|
+
const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
|
|
17793
|
+
content = doc2.content;
|
|
17794
|
+
}
|
|
17795
|
+
if (optionsJSON) {
|
|
17796
|
+
content = this.editor.schema.nodeFromJSON(optionsJSON);
|
|
17797
|
+
}
|
|
17798
|
+
if (!content?.content?.length) {
|
|
17799
|
+
content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
|
|
17800
|
+
}
|
|
17801
|
+
if (!options.id) {
|
|
17802
|
+
const allSections = SectionHelpers.getAllSections(editor);
|
|
17803
|
+
options.id = allSections.length + 1;
|
|
17804
|
+
}
|
|
17805
|
+
if (!options.title) {
|
|
17806
|
+
options.title = "Document section";
|
|
17807
|
+
}
|
|
17808
|
+
const node = this.type.createAndFill(options, content);
|
|
17809
|
+
if (!node) return false;
|
|
17810
|
+
const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
|
|
17811
|
+
if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
|
|
17812
|
+
const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
|
|
17813
|
+
from2 = insertPos2;
|
|
17814
|
+
to = insertPos2;
|
|
17815
|
+
}
|
|
17816
|
+
tr.replaceRangeWith(from2, to, node);
|
|
17817
|
+
const nodeEnd = from2 + node.nodeSize;
|
|
17818
|
+
let shouldInsertParagraph = true;
|
|
17819
|
+
let insertPos = nodeEnd;
|
|
17820
|
+
if (nodeEnd >= tr.doc.content.size) {
|
|
17821
|
+
insertPos = tr.doc.content.size;
|
|
17822
|
+
if (insertPos > 0) {
|
|
17823
|
+
const $endPos = tr.doc.resolve(insertPos);
|
|
17824
|
+
if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
|
|
17825
|
+
shouldInsertParagraph = false;
|
|
17826
|
+
}
|
|
17827
|
+
}
|
|
17828
|
+
}
|
|
17829
|
+
if (shouldInsertParagraph) {
|
|
17830
|
+
const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
|
|
17831
|
+
tr.insert(insertPos, emptyParagraph);
|
|
17832
|
+
}
|
|
17833
|
+
if (dispatch) {
|
|
17834
|
+
tr.setMeta("documentSection", { action: "create" });
|
|
17835
|
+
dispatch(tr);
|
|
17836
|
+
setTimeout(() => {
|
|
17837
|
+
try {
|
|
17838
|
+
const currentState = editor.state;
|
|
17839
|
+
const docSize = currentState.doc.content.size;
|
|
17840
|
+
let targetPos = from2 + node.nodeSize;
|
|
17841
|
+
if (shouldInsertParagraph) {
|
|
17842
|
+
targetPos += 1;
|
|
17843
|
+
}
|
|
17844
|
+
targetPos = Math.min(targetPos, docSize);
|
|
17845
|
+
if (targetPos < docSize && targetPos > 0) {
|
|
17846
|
+
const newSelection = Selection.near(currentState.doc.resolve(targetPos));
|
|
17847
|
+
const newTr = currentState.tr.setSelection(newSelection);
|
|
17848
|
+
editor.view.dispatch(newTr);
|
|
17849
|
+
}
|
|
17850
|
+
} catch (e) {
|
|
17851
|
+
console.warn("Could not set delayed selection:", e);
|
|
17852
|
+
}
|
|
17853
|
+
}, 0);
|
|
17854
|
+
}
|
|
17855
|
+
return true;
|
|
17856
|
+
},
|
|
17857
|
+
/**
|
|
17858
|
+
* Remove section wrapper at cursor, preserving its content
|
|
17859
|
+
* @category Command
|
|
17860
|
+
* @example
|
|
17861
|
+
* editor.commands.removeSectionAtSelection()
|
|
17862
|
+
* @note Content stays in document, only section wrapper is removed
|
|
17863
|
+
*/
|
|
17864
|
+
removeSectionAtSelection: () => ({ tr, dispatch }) => {
|
|
17865
|
+
const sdtNode = findParentNode((node2) => node2.type.name === "documentSection")(tr.selection);
|
|
17866
|
+
if (!sdtNode) return false;
|
|
17867
|
+
const { node, pos } = sdtNode;
|
|
17868
|
+
const nodeStart = pos;
|
|
17869
|
+
const nodeEnd = nodeStart + node.nodeSize;
|
|
17870
|
+
const contentToPreserve = node.content;
|
|
17871
|
+
tr.delete(nodeStart, nodeEnd);
|
|
17872
|
+
if (contentToPreserve.size > 0) {
|
|
17873
|
+
tr.insert(nodeStart, contentToPreserve);
|
|
17874
|
+
}
|
|
17875
|
+
const newPos = Math.min(nodeStart, tr.doc.content.size);
|
|
17876
|
+
tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
|
|
17877
|
+
if (dispatch) {
|
|
17878
|
+
tr.setMeta("documentSection", { action: "delete" });
|
|
17879
|
+
dispatch(tr);
|
|
17880
|
+
}
|
|
17881
|
+
return true;
|
|
17882
|
+
},
|
|
17883
|
+
/**
|
|
17884
|
+
* Delete section and all its content
|
|
17885
|
+
* @category Command
|
|
17886
|
+
* @param {number} id - Section to delete
|
|
17887
|
+
* @example
|
|
17888
|
+
* editor.commands.removeSectionById(123)
|
|
17889
|
+
*/
|
|
17890
|
+
removeSectionById: (id) => ({ tr, dispatch }) => {
|
|
17891
|
+
const sections = SectionHelpers.getAllSections(this.editor);
|
|
17892
|
+
const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
|
|
17893
|
+
if (!sectionToRemove) return false;
|
|
17894
|
+
const { pos, node } = sectionToRemove;
|
|
17895
|
+
const nodeStart = pos;
|
|
17896
|
+
const nodeEnd = nodeStart + node.nodeSize;
|
|
17897
|
+
tr.delete(nodeStart, nodeEnd);
|
|
17898
|
+
if (dispatch) {
|
|
17899
|
+
tr.setMeta("documentSection", { action: "delete", id });
|
|
17900
|
+
dispatch(tr);
|
|
17901
|
+
}
|
|
17902
|
+
return true;
|
|
17903
|
+
},
|
|
17904
|
+
/**
|
|
17905
|
+
* Lock section against edits
|
|
17906
|
+
* @category Command
|
|
17907
|
+
* @param {number} id - Section to lock
|
|
17908
|
+
* @example
|
|
17909
|
+
* editor.commands.lockSectionById(123)
|
|
17910
|
+
*/
|
|
17911
|
+
lockSectionById: (id) => ({ tr, dispatch }) => {
|
|
17912
|
+
const sections = SectionHelpers.getAllSections(this.editor);
|
|
17913
|
+
const sectionToLock = sections.find(({ node }) => node.attrs.id === id);
|
|
17914
|
+
if (!sectionToLock) return false;
|
|
17915
|
+
tr.setNodeMarkup(sectionToLock.pos, null, { ...sectionToLock.node.attrs, isLocked: true });
|
|
17916
|
+
if (dispatch) {
|
|
17917
|
+
tr.setMeta("documentSection", { action: "lock", id });
|
|
17918
|
+
dispatch(tr);
|
|
17919
|
+
}
|
|
17920
|
+
return true;
|
|
17921
|
+
},
|
|
17922
|
+
/**
|
|
17923
|
+
* Modify section attributes or content
|
|
17924
|
+
* @category Command
|
|
17925
|
+
* @param {SectionUpdate} options - Changes to apply
|
|
17926
|
+
* @example
|
|
17927
|
+
* editor.commands.updateSectionById({ id: 123, attrs: { isLocked: false } })
|
|
17928
|
+
* editor.commands.updateSectionById({ id: 123, html: '<p>New content</p>' })
|
|
17929
|
+
* editor.commands.updateSectionById({
|
|
17930
|
+
* id: 123,
|
|
17931
|
+
* html: '<p>Updated</p>',
|
|
17932
|
+
* attrs: { title: 'New Title' }
|
|
17933
|
+
* })
|
|
17934
|
+
*/
|
|
17935
|
+
updateSectionById: ({ id, html, json, attrs }) => ({ tr, dispatch, editor }) => {
|
|
17936
|
+
const sections = SectionHelpers.getAllSections(editor || this.editor);
|
|
17937
|
+
const sectionToUpdate = sections.find(({ node: node2 }) => node2.attrs.id === id);
|
|
17938
|
+
if (!sectionToUpdate) return false;
|
|
17939
|
+
const { pos, node } = sectionToUpdate;
|
|
17940
|
+
let newContent = null;
|
|
17941
|
+
if (html) {
|
|
17942
|
+
const htmlDoc = htmlHandler(html, editor || this.editor);
|
|
17943
|
+
const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
|
|
17944
|
+
newContent = doc2.content;
|
|
17945
|
+
}
|
|
17946
|
+
if (json) {
|
|
17947
|
+
newContent = (editor || this.editor).schema.nodeFromJSON(json);
|
|
17948
|
+
}
|
|
17949
|
+
if (!newContent) {
|
|
17950
|
+
newContent = node.content;
|
|
17951
|
+
}
|
|
17952
|
+
const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
|
|
17953
|
+
tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
|
|
17954
|
+
if (dispatch) {
|
|
17955
|
+
tr.setMeta("documentSection", { action: "update", id, attrs });
|
|
17956
|
+
dispatch(tr);
|
|
17957
|
+
}
|
|
17958
|
+
return true;
|
|
17959
|
+
}
|
|
17960
|
+
};
|
|
17961
|
+
},
|
|
17962
|
+
addHelpers() {
|
|
17963
|
+
return {
|
|
17964
|
+
...SectionHelpers
|
|
17965
|
+
};
|
|
17966
|
+
}
|
|
17967
|
+
});
|
|
17968
|
+
const Document = Node$1.create({
|
|
17969
|
+
name: "doc",
|
|
17970
|
+
topNode: true,
|
|
17971
|
+
content: "block+",
|
|
17972
|
+
parseDOM() {
|
|
17973
|
+
return [{ tag: "doc" }];
|
|
17974
|
+
},
|
|
17975
|
+
renderDOM() {
|
|
17976
|
+
return ["doc", 0];
|
|
17977
|
+
},
|
|
17978
|
+
addAttributes() {
|
|
17979
|
+
return {
|
|
17980
|
+
attributes: {
|
|
17981
|
+
rendered: false,
|
|
17982
|
+
"aria-label": "Document node"
|
|
17983
|
+
}
|
|
17984
|
+
};
|
|
17985
|
+
},
|
|
17986
|
+
addCommands() {
|
|
17987
|
+
return {
|
|
17988
|
+
/**
|
|
17989
|
+
* Get document statistics
|
|
17990
|
+
* @category Command
|
|
17991
|
+
* @example
|
|
17992
|
+
* // Get word and character count
|
|
17993
|
+
* const stats = editor.commands.getDocumentStats()
|
|
17994
|
+
* console.log(`${stats.words} words, ${stats.characters} characters`)
|
|
17995
|
+
* @note Returns word count, character count, and paragraph count
|
|
17996
|
+
*/
|
|
17997
|
+
getDocumentStats: () => ({ editor }) => {
|
|
17998
|
+
const text = editor.getText();
|
|
17999
|
+
const words = text.split(/\s+/).filter((word) => word.length > 0).length;
|
|
18000
|
+
const characters = text.length;
|
|
18001
|
+
const paragraphs = editor.state.doc.content.childCount;
|
|
18002
|
+
return {
|
|
18003
|
+
words,
|
|
18004
|
+
characters,
|
|
18005
|
+
paragraphs
|
|
18006
|
+
};
|
|
18007
|
+
},
|
|
18008
|
+
/**
|
|
18009
|
+
* Clear entire document
|
|
18010
|
+
* @category Command
|
|
18011
|
+
* @example
|
|
18012
|
+
* editor.commands.clearDocument()
|
|
18013
|
+
* @note Replaces all content with an empty paragraph
|
|
18014
|
+
*/
|
|
18015
|
+
clearDocument: () => ({ commands: commands2 }) => {
|
|
18016
|
+
return commands2.setContent("<p></p>");
|
|
18017
|
+
}
|
|
18018
|
+
};
|
|
18019
|
+
}
|
|
18020
|
+
});
|
|
18021
|
+
const Text = Node$1.create({
|
|
18022
|
+
name: "text",
|
|
18023
|
+
group: "inline",
|
|
18024
|
+
inline: true,
|
|
18025
|
+
addOptions() {
|
|
18026
|
+
return {};
|
|
18027
|
+
}
|
|
18028
|
+
});
|
|
18029
|
+
const splitRun = () => (props) => {
|
|
18030
|
+
const { state, view, tr } = props;
|
|
18031
|
+
const { $from, empty: empty2 } = state.selection;
|
|
18032
|
+
if (!empty2) return false;
|
|
18033
|
+
if ($from.parent.type.name !== "run") return false;
|
|
18034
|
+
const handled = splitBlock(state, (transaction) => {
|
|
18035
|
+
view.dispatch(transaction);
|
|
18036
|
+
});
|
|
18037
|
+
if (handled) {
|
|
18038
|
+
tr.setMeta("preventDispatch", true);
|
|
18039
|
+
}
|
|
18040
|
+
return handled;
|
|
18041
|
+
};
|
|
18042
|
+
const Run = OxmlNode.create({
|
|
18043
|
+
name: "run",
|
|
18044
|
+
oXmlName: "w:r",
|
|
18045
|
+
group: "inline",
|
|
18046
|
+
inline: true,
|
|
18047
|
+
content: "inline*",
|
|
18048
|
+
selectable: false,
|
|
18049
|
+
childToAttributes: ["runProperties"],
|
|
18050
|
+
addOptions() {
|
|
18051
|
+
return {
|
|
18052
|
+
htmlAttributes: {
|
|
18053
|
+
"data-run": "1"
|
|
18054
|
+
}
|
|
18055
|
+
};
|
|
18056
|
+
},
|
|
18057
|
+
addAttributes() {
|
|
18058
|
+
return {
|
|
18059
|
+
runProperties: {
|
|
18060
|
+
default: null,
|
|
18061
|
+
rendered: false,
|
|
18062
|
+
keepOnSplit: true
|
|
18063
|
+
},
|
|
18064
|
+
rsidR: {
|
|
18065
|
+
default: null,
|
|
18066
|
+
rendered: false,
|
|
18067
|
+
keepOnSplit: true
|
|
18068
|
+
},
|
|
18069
|
+
rsidRPr: {
|
|
18070
|
+
default: null,
|
|
18071
|
+
rendered: false,
|
|
18072
|
+
keepOnSplit: true
|
|
18073
|
+
},
|
|
18074
|
+
rsidDel: {
|
|
18075
|
+
default: null,
|
|
18076
|
+
rendered: false,
|
|
18077
|
+
keepOnSplit: true
|
|
18078
|
+
}
|
|
18079
|
+
};
|
|
18080
|
+
},
|
|
18081
|
+
addCommands() {
|
|
18082
|
+
return {
|
|
18083
|
+
splitRun
|
|
18084
|
+
};
|
|
18085
|
+
},
|
|
18086
|
+
parseDOM() {
|
|
18087
|
+
return [{ tag: "span[data-run]" }];
|
|
18088
|
+
},
|
|
18089
|
+
renderDOM({ htmlAttributes }) {
|
|
18090
|
+
const base2 = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
|
|
18091
|
+
return ["span", base2, 0];
|
|
18092
|
+
}
|
|
18093
|
+
});
|
|
18094
|
+
const inputRegex$1 = /^\s*([-+*])\s$/;
|
|
18095
|
+
const BulletList = Node$1.create({
|
|
18096
|
+
name: "bulletList",
|
|
18097
|
+
group: "block list",
|
|
18098
|
+
selectable: false,
|
|
18099
|
+
content() {
|
|
18100
|
+
return `${this.options.itemTypeName}+`;
|
|
18101
|
+
},
|
|
18102
|
+
addOptions() {
|
|
18103
|
+
return {
|
|
18104
|
+
itemTypeName: "listItem",
|
|
18105
|
+
htmlAttributes: {
|
|
18106
|
+
"aria-label": "Bullet list node"
|
|
18107
|
+
},
|
|
18108
|
+
keepMarks: true,
|
|
18109
|
+
keepAttributes: false
|
|
18110
|
+
};
|
|
18111
|
+
},
|
|
18112
|
+
parseDOM() {
|
|
18113
|
+
return [{ tag: "ul" }];
|
|
18114
|
+
},
|
|
18115
|
+
renderDOM({ htmlAttributes }) {
|
|
18116
|
+
const attributes = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
|
|
18117
|
+
return ["ul", attributes, 0];
|
|
18118
|
+
},
|
|
18119
|
+
addAttributes() {
|
|
18120
|
+
return {
|
|
18121
|
+
"list-style-type": {
|
|
18122
|
+
default: "bullet",
|
|
18123
|
+
rendered: false
|
|
18124
|
+
},
|
|
18125
|
+
listId: {
|
|
18126
|
+
rendered: false
|
|
18127
|
+
},
|
|
18128
|
+
sdBlockId: {
|
|
18129
|
+
default: null,
|
|
18130
|
+
keepOnSplit: false,
|
|
18131
|
+
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
18132
|
+
renderDOM: (attrs) => {
|
|
18133
|
+
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
18134
|
+
}
|
|
18135
|
+
},
|
|
18136
|
+
attributes: {
|
|
18137
|
+
rendered: false,
|
|
18138
|
+
keepOnSplit: true
|
|
18139
|
+
}
|
|
18140
|
+
};
|
|
18141
|
+
},
|
|
18142
|
+
addCommands() {
|
|
18143
|
+
return {
|
|
18144
|
+
/**
|
|
18145
|
+
* Toggle a bullet list at the current selection
|
|
18146
|
+
* @category Command
|
|
18147
|
+
* @example
|
|
18148
|
+
* // Toggle bullet list on selected text
|
|
18149
|
+
* editor.commands.toggleBulletList()
|
|
18150
|
+
* @note Converts selected paragraphs to list items or removes list formatting
|
|
18151
|
+
*/
|
|
18152
|
+
toggleBulletList: () => (params2) => {
|
|
18153
|
+
return toggleList(this.type)(params2);
|
|
18154
|
+
}
|
|
18155
|
+
};
|
|
18156
|
+
},
|
|
18157
|
+
addShortcuts() {
|
|
18158
|
+
return {
|
|
18159
|
+
"Mod-Shift-8": () => {
|
|
18160
|
+
return this.editor.commands.toggleBulletList();
|
|
18161
|
+
}
|
|
18162
|
+
};
|
|
18163
|
+
},
|
|
18164
|
+
addInputRules() {
|
|
18165
|
+
return [
|
|
18166
|
+
new InputRule({
|
|
18167
|
+
match: inputRegex$1,
|
|
18168
|
+
handler: ({ state, range }) => {
|
|
18169
|
+
const $pos = state.selection.$from;
|
|
18170
|
+
const listItemType = state.schema.nodes.listItem;
|
|
18171
|
+
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
18172
|
+
if ($pos.node(depth).type === listItemType) {
|
|
18173
|
+
return null;
|
|
18174
|
+
}
|
|
18175
|
+
}
|
|
18176
|
+
const { tr } = state;
|
|
18177
|
+
tr.delete(range.from, range.to);
|
|
18178
|
+
ListHelpers.createNewList({
|
|
18179
|
+
listType: this.type,
|
|
18180
|
+
tr,
|
|
18181
|
+
editor: this.editor
|
|
18182
|
+
});
|
|
18183
|
+
}
|
|
18184
|
+
})
|
|
18185
|
+
];
|
|
18186
|
+
}
|
|
18187
|
+
});
|
|
18188
|
+
const inputRegex = /^(\d+)\.\s$/;
|
|
18189
|
+
const OrderedList = Node$1.create({
|
|
18190
|
+
name: "orderedList",
|
|
18191
|
+
group: "block list",
|
|
18192
|
+
selectable: false,
|
|
18193
|
+
content() {
|
|
18194
|
+
return `${this.options.itemTypeName}+`;
|
|
18195
|
+
},
|
|
18196
|
+
addOptions() {
|
|
18197
|
+
return {
|
|
18198
|
+
itemTypeName: "listItem",
|
|
18199
|
+
htmlAttributes: {
|
|
18200
|
+
"aria-label": "Ordered list node"
|
|
18201
|
+
},
|
|
18202
|
+
keepMarks: true,
|
|
18203
|
+
keepAttributes: false,
|
|
18204
|
+
listStyleTypes: ["decimal", "lowerAlpha", "lowerRoman"]
|
|
18205
|
+
};
|
|
18206
|
+
},
|
|
18207
|
+
addAttributes() {
|
|
18208
|
+
return {
|
|
18209
|
+
order: {
|
|
18210
|
+
default: 1,
|
|
18211
|
+
parseDOM: (element) => {
|
|
18212
|
+
return element.hasAttribute("start") ? parseInt(element.getAttribute("start") || "", 10) : 1;
|
|
18213
|
+
},
|
|
18214
|
+
renderDOM: (attrs) => {
|
|
18215
|
+
return {
|
|
18216
|
+
start: attrs.order
|
|
18217
|
+
};
|
|
18218
|
+
}
|
|
18219
|
+
},
|
|
18220
|
+
sdBlockId: {
|
|
18221
|
+
default: null,
|
|
18222
|
+
keepOnSplit: false,
|
|
18223
|
+
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
18224
|
+
renderDOM: (attrs) => {
|
|
18225
|
+
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
18226
|
+
}
|
|
18227
|
+
},
|
|
18228
|
+
syncId: {
|
|
18229
|
+
default: null,
|
|
18230
|
+
parseDOM: (elem) => elem.getAttribute("data-sync-id"),
|
|
18231
|
+
renderDOM: (attrs) => {
|
|
18232
|
+
if (!attrs.syncId) return {};
|
|
18233
|
+
return {
|
|
18234
|
+
"data-sync-id": attrs.syncId
|
|
18235
|
+
};
|
|
18236
|
+
}
|
|
18237
|
+
// rendered: false,
|
|
18238
|
+
},
|
|
18239
|
+
listId: {
|
|
18240
|
+
keepOnSplit: true,
|
|
18241
|
+
parseDOM: (elem) => elem.getAttribute("data-list-id"),
|
|
18242
|
+
renderDOM: (attrs) => {
|
|
18243
|
+
if (!attrs.listId) return {};
|
|
18244
|
+
return {
|
|
18245
|
+
"data-list-id": attrs.listId
|
|
18246
|
+
};
|
|
18247
|
+
}
|
|
18248
|
+
},
|
|
18249
|
+
"list-style-type": {
|
|
18250
|
+
default: "decimal",
|
|
18251
|
+
rendered: false
|
|
18252
|
+
},
|
|
18253
|
+
attributes: {
|
|
18254
|
+
rendered: false,
|
|
18255
|
+
keepOnSplit: true
|
|
18256
|
+
}
|
|
18257
|
+
};
|
|
18258
|
+
},
|
|
18259
|
+
parseDOM() {
|
|
18260
|
+
return [{ tag: "ol" }];
|
|
18261
|
+
},
|
|
18262
|
+
renderDOM({ htmlAttributes }) {
|
|
18263
|
+
const { start: start2, ...restAttributes } = htmlAttributes;
|
|
18264
|
+
return start2 === 1 ? ["ol", Attribute.mergeAttributes(this.options.htmlAttributes, restAttributes), 0] : ["ol", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
18265
|
+
},
|
|
18266
|
+
addCommands() {
|
|
18267
|
+
return {
|
|
18268
|
+
/**
|
|
18269
|
+
* Toggle ordered list formatting
|
|
18270
|
+
* @category Command
|
|
18271
|
+
* @example
|
|
18272
|
+
* editor.commands.toggleOrderedList()
|
|
18273
|
+
* @note Converts selection to ordered list or back to paragraphs
|
|
18274
|
+
*/
|
|
18275
|
+
toggleOrderedList: () => (params2) => {
|
|
18276
|
+
return toggleList(this.type)(params2);
|
|
18277
|
+
},
|
|
18278
|
+
/**
|
|
18279
|
+
* Restart list node numbering
|
|
18280
|
+
* @category Command
|
|
18281
|
+
* @param {Array} followingNodes - Nodes to restart
|
|
18282
|
+
* @param {number} pos - Starting position
|
|
18283
|
+
* @example
|
|
18284
|
+
* editor.commands.restartListNodes(nodes, position)
|
|
18285
|
+
* @note Resets list numbering for specified nodes
|
|
18286
|
+
*/
|
|
18287
|
+
restartListNodes: (followingNodes, pos) => ({ tr }) => {
|
|
18288
|
+
let currentNodePos = pos;
|
|
18289
|
+
const nodes = followingNodes.map((node) => {
|
|
18290
|
+
const resultNode = {
|
|
18291
|
+
node,
|
|
18292
|
+
pos: currentNodePos
|
|
18293
|
+
};
|
|
18294
|
+
currentNodePos += node.nodeSize;
|
|
18295
|
+
return resultNode;
|
|
18296
|
+
});
|
|
18297
|
+
nodes.forEach((item) => {
|
|
18298
|
+
const { pos: pos2 } = item;
|
|
18299
|
+
const newPos = tr.mapping.map(pos2);
|
|
18300
|
+
tr.setNodeMarkup(newPos, void 0, {});
|
|
18301
|
+
});
|
|
18302
|
+
return true;
|
|
18303
|
+
},
|
|
18304
|
+
/**
|
|
18305
|
+
* Update ordered list style type based on nesting level
|
|
18306
|
+
* @category Command
|
|
18307
|
+
* @example
|
|
18308
|
+
* editor.commands.updateOrderedListStyleType()
|
|
18309
|
+
* @note Cycles through decimal -> lowerAlpha -> lowerRoman based on depth
|
|
18310
|
+
*/
|
|
18311
|
+
updateOrderedListStyleType: () => ({ dispatch, tr }) => {
|
|
18312
|
+
let list = findParentNode((node) => node.type.name === this.name)(tr.selection);
|
|
18313
|
+
if (!list) {
|
|
18314
|
+
return true;
|
|
18315
|
+
}
|
|
18316
|
+
if (dispatch) {
|
|
18317
|
+
let listLevel = (list.depth - 1) / 2;
|
|
18318
|
+
let listStyleTypes = this.options.listStyleTypes;
|
|
18319
|
+
let listStyle = listStyleTypes[listLevel % listStyleTypes.length];
|
|
18320
|
+
let currentListStyle = list.node.attrs["list-style-type"];
|
|
18321
|
+
let nodeAtPos = tr.doc.nodeAt(list.pos);
|
|
18322
|
+
if (currentListStyle !== listStyle && nodeAtPos.eq(list.node)) {
|
|
18323
|
+
tr.setNodeMarkup(list.pos, void 0, {
|
|
18324
|
+
...list.node.attrs,
|
|
18325
|
+
...{
|
|
18326
|
+
"list-style-type": listStyle
|
|
18327
|
+
}
|
|
18328
|
+
});
|
|
18329
|
+
}
|
|
18330
|
+
}
|
|
18331
|
+
return true;
|
|
18332
|
+
}
|
|
18333
|
+
};
|
|
18334
|
+
},
|
|
18335
|
+
addShortcuts() {
|
|
18336
|
+
return {
|
|
18337
|
+
"Mod-Shift-7": () => {
|
|
18338
|
+
return this.editor.commands.toggleOrderedList();
|
|
18339
|
+
}
|
|
18340
|
+
};
|
|
18341
|
+
},
|
|
18342
|
+
addInputRules() {
|
|
18343
|
+
return [
|
|
18344
|
+
new InputRule({
|
|
18345
|
+
match: inputRegex,
|
|
18346
|
+
handler: ({ state, range }) => {
|
|
18347
|
+
const $pos = state.selection.$from;
|
|
18348
|
+
const listItemType = state.schema.nodes.listItem;
|
|
18349
|
+
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
18350
|
+
if ($pos.node(depth).type === listItemType) {
|
|
18351
|
+
return null;
|
|
18352
|
+
}
|
|
18353
|
+
}
|
|
18354
|
+
const { tr } = state;
|
|
18355
|
+
tr.delete(range.from, range.to);
|
|
18356
|
+
ListHelpers.createNewList({
|
|
18357
|
+
listType: this.type,
|
|
18358
|
+
tr,
|
|
18359
|
+
editor: this.editor
|
|
18360
|
+
});
|
|
18361
|
+
}
|
|
18362
|
+
})
|
|
18363
|
+
];
|
|
18364
|
+
}
|
|
18365
|
+
});
|
|
18366
|
+
const generateOrderedListIndex = ({ listLevel, lvlText, listNumberingType, customFormat }) => {
|
|
18367
|
+
const handler = listIndexMap[listNumberingType];
|
|
18368
|
+
return handler ? handler(listLevel, lvlText, customFormat) : null;
|
|
18369
|
+
};
|
|
18370
|
+
const handleDecimal = (path, lvlText) => generateNumbering(path, lvlText, String);
|
|
18371
|
+
const handleRoman = (path, lvlText) => generateNumbering(path, lvlText, intToRoman);
|
|
18372
|
+
const handleLowerRoman = (path, lvlText) => handleRoman(path, lvlText).toLowerCase();
|
|
18373
|
+
const handleLowerAlpha = (path, lvlText) => handleAlpha(path, lvlText).toLowerCase();
|
|
18374
|
+
const handleAlpha = (path, lvlText) => generateNumbering(path, lvlText, (p) => intToAlpha(p));
|
|
18375
|
+
const handleOrdinal = (path, lvlText) => generateNumbering(path, lvlText, ordinalFormatter);
|
|
18376
|
+
const handleCustom = (path, lvlText, customFormat) => generateFromCustom(path, lvlText, customFormat);
|
|
18377
|
+
const handleJapaneseCounting = (path, lvlText) => generateNumbering(path, lvlText, intToJapaneseCounting);
|
|
18378
|
+
const listIndexMap = {
|
|
18379
|
+
decimal: handleDecimal,
|
|
18380
|
+
lowerRoman: handleLowerRoman,
|
|
18381
|
+
upperRoman: handleRoman,
|
|
18382
|
+
lowerLetter: handleLowerAlpha,
|
|
18383
|
+
upperLetter: handleAlpha,
|
|
18384
|
+
ordinal: handleOrdinal,
|
|
18385
|
+
custom: handleCustom,
|
|
18386
|
+
japaneseCounting: handleJapaneseCounting
|
|
18387
|
+
};
|
|
18388
|
+
const createNumbering = (values, lvlText) => {
|
|
18389
|
+
return values.reduce((acc, value, index2) => {
|
|
18390
|
+
return value > 9 ? acc.replace(/^0/, "").replace(`%${index2 + 1}`, value) : acc.replace(`%${index2 + 1}`, value);
|
|
18391
|
+
}, lvlText);
|
|
18392
|
+
};
|
|
18393
|
+
const generateNumbering = (path, lvlText, formatter) => {
|
|
18394
|
+
const formattedValues = path.map(formatter);
|
|
18395
|
+
return createNumbering(formattedValues, lvlText);
|
|
18396
|
+
};
|
|
18397
|
+
const ordinalFormatter = (level) => {
|
|
18398
|
+
const suffixes = ["th", "st", "nd", "rd"];
|
|
18399
|
+
const value = level % 100;
|
|
18400
|
+
const suffix = suffixes[(value - 20) % 10] || suffixes[value] || suffixes[0];
|
|
18401
|
+
const p = level + suffix;
|
|
18402
|
+
return p;
|
|
18403
|
+
};
|
|
18404
|
+
const generateFromCustom = (path, lvlText, customFormat) => {
|
|
18405
|
+
if (customFormat !== "001, 002, 003, ...") return generateNumbering(path, lvlText, String);
|
|
18406
|
+
const match = customFormat.match(/(\d+)/);
|
|
18407
|
+
if (!match) throw new Error("Invalid format string: no numeric pattern found");
|
|
18408
|
+
const sample = match[1];
|
|
18409
|
+
const digitCount = sample.length;
|
|
18410
|
+
const index2 = path.pop();
|
|
18411
|
+
return String(index2).padStart(digitCount, "0");
|
|
18412
|
+
};
|
|
18413
|
+
const intToRoman = (num) => {
|
|
18414
|
+
const romanNumeralMap = [
|
|
18415
|
+
{ value: 1e3, numeral: "M" },
|
|
18416
|
+
{ value: 900, numeral: "CM" },
|
|
18417
|
+
{ value: 500, numeral: "D" },
|
|
18418
|
+
{ value: 400, numeral: "CD" },
|
|
18419
|
+
{ value: 100, numeral: "C" },
|
|
18420
|
+
{ value: 90, numeral: "XC" },
|
|
18421
|
+
{ value: 50, numeral: "L" },
|
|
18422
|
+
{ value: 40, numeral: "XL" },
|
|
18423
|
+
{ value: 10, numeral: "X" },
|
|
18424
|
+
{ value: 9, numeral: "IX" },
|
|
18425
|
+
{ value: 5, numeral: "V" },
|
|
18426
|
+
{ value: 4, numeral: "IV" },
|
|
18427
|
+
{ value: 1, numeral: "I" }
|
|
18428
|
+
];
|
|
18429
|
+
let result = "";
|
|
18430
|
+
for (const { value, numeral } of romanNumeralMap) {
|
|
18431
|
+
while (num >= value) {
|
|
18432
|
+
result += numeral;
|
|
18433
|
+
num -= value;
|
|
18434
|
+
}
|
|
18435
|
+
}
|
|
18436
|
+
return result;
|
|
18437
|
+
};
|
|
18438
|
+
const intToAlpha = (num) => {
|
|
18439
|
+
let result = "";
|
|
18440
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
18441
|
+
while (num > 0) {
|
|
18442
|
+
let index2 = (num - 1) % 26;
|
|
18443
|
+
result = alphabet[index2] + result;
|
|
18444
|
+
num = Math.floor((num - 1) / 26);
|
|
18445
|
+
}
|
|
18446
|
+
return result;
|
|
18447
|
+
};
|
|
18448
|
+
const intToJapaneseCounting = (num) => {
|
|
18449
|
+
const digits = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
|
|
18450
|
+
const units = ["", "十", "百", "千"];
|
|
18451
|
+
if (num === 0) return "零";
|
|
18452
|
+
if (num < 10) return digits[num];
|
|
18453
|
+
let result = "";
|
|
18454
|
+
let tempNum = num;
|
|
18455
|
+
let unitIndex = 0;
|
|
18456
|
+
while (tempNum > 0) {
|
|
18457
|
+
const digit = tempNum % 10;
|
|
18458
|
+
if (digit !== 0) {
|
|
18459
|
+
const digitStr = digit === 1 && unitIndex > 0 ? "" : digits[digit];
|
|
18460
|
+
result = digitStr + (unitIndex > 0 ? units[unitIndex] : "") + result;
|
|
18461
|
+
} else if (result && tempNum > 0) {
|
|
18462
|
+
if (!result.startsWith("零") && tempNum % 100 !== 0) {
|
|
18463
|
+
result = "零" + result;
|
|
18464
|
+
}
|
|
18465
|
+
}
|
|
18466
|
+
tempNum = Math.floor(tempNum / 10);
|
|
18467
|
+
unitIndex++;
|
|
18468
|
+
if (unitIndex > 3) break;
|
|
18469
|
+
}
|
|
18470
|
+
if (num >= 10 && num < 20) {
|
|
18471
|
+
result = result.replace(/^一十/, "十");
|
|
18472
|
+
}
|
|
18473
|
+
return result;
|
|
18474
|
+
};
|
|
18475
|
+
const isKeyboardInvocation = (event) => {
|
|
18476
|
+
return event.type === "contextmenu" && typeof event.detail === "number" && event.detail === 0 && (event.button === 0 || event.button === void 0) && event.clientX === 0 && event.clientY === 0;
|
|
18477
|
+
};
|
|
18478
|
+
const prefersNativeMenu = (event) => {
|
|
18479
|
+
if (!event) return false;
|
|
18480
|
+
if (event.ctrlKey || event.metaKey) {
|
|
18481
|
+
return true;
|
|
18482
|
+
}
|
|
18483
|
+
return isKeyboardInvocation(event);
|
|
18484
|
+
};
|
|
18485
|
+
const shouldAllowNativeContextMenu = (event) => {
|
|
18486
|
+
return prefersNativeMenu(event);
|
|
18487
|
+
};
|
|
18488
|
+
const shouldBypassContextMenu = shouldAllowNativeContextMenu;
|
|
18489
|
+
const DEFAULT_SELECTION_STATE = Object.freeze({
|
|
18490
|
+
focused: false,
|
|
18491
|
+
preservedSelection: null,
|
|
18492
|
+
showVisualSelection: false,
|
|
18493
|
+
skipFocusReset: false
|
|
18494
|
+
});
|
|
18495
|
+
const normalizeSelectionState = (state = {}) => ({
|
|
18496
|
+
...DEFAULT_SELECTION_STATE,
|
|
18497
|
+
...state
|
|
18498
|
+
});
|
|
18499
|
+
const CustomSelectionPluginKey = new PluginKey("CustomSelection");
|
|
18500
|
+
const handleClickOutside = (event, editor) => {
|
|
18501
|
+
const editorElem = editor?.options?.element;
|
|
18502
|
+
if (!editorElem) return;
|
|
18503
|
+
const isInsideEditor = editorElem?.contains(event.target);
|
|
18504
|
+
if (!isInsideEditor) {
|
|
18505
|
+
editor.setOptions({
|
|
18506
|
+
focusTarget: event.target
|
|
18507
|
+
});
|
|
18508
|
+
} else {
|
|
18509
|
+
editor.setOptions({
|
|
18510
|
+
focusTarget: null
|
|
18511
|
+
});
|
|
18512
|
+
}
|
|
18513
|
+
};
|
|
18514
|
+
function getFocusMeta(tr) {
|
|
18515
|
+
return tr.getMeta(CustomSelectionPluginKey);
|
|
18516
|
+
}
|
|
18517
|
+
function setFocusMeta(tr, value) {
|
|
18518
|
+
return tr.setMeta(CustomSelectionPluginKey, value);
|
|
18519
|
+
}
|
|
18520
|
+
function getFocusState(state) {
|
|
18521
|
+
return CustomSelectionPluginKey.getState(state);
|
|
18522
|
+
}
|
|
18523
|
+
const isToolbarInput = (target) => {
|
|
18524
|
+
return !!target?.closest(".button-text-input") || target?.classList?.contains("button-text-input");
|
|
18525
|
+
};
|
|
18526
|
+
const isToolbarButton = (target) => {
|
|
18527
|
+
return !!target?.closest(".toolbar-button") || target?.classList?.contains("toolbar-button");
|
|
18528
|
+
};
|
|
18529
|
+
const CustomSelection = Extension.create({
|
|
18530
|
+
name: "customSelection",
|
|
18531
|
+
addPmPlugins() {
|
|
18532
|
+
const editor = this.editor;
|
|
18533
|
+
const customSelectionPlugin = new Plugin({
|
|
18534
|
+
key: CustomSelectionPluginKey,
|
|
18535
|
+
state: {
|
|
18536
|
+
init: () => ({ ...DEFAULT_SELECTION_STATE }),
|
|
18537
|
+
apply: (tr, value) => {
|
|
18538
|
+
const meta = getFocusMeta(tr);
|
|
18539
|
+
if (meta !== void 0) {
|
|
18540
|
+
return { ...value, ...meta };
|
|
18541
|
+
}
|
|
18542
|
+
return value;
|
|
18543
|
+
}
|
|
18544
|
+
},
|
|
18545
|
+
view: () => {
|
|
18546
|
+
const clickHandler = (event) => handleClickOutside(event, editor);
|
|
18547
|
+
document?.addEventListener("mousedown", clickHandler);
|
|
18548
|
+
return {
|
|
18549
|
+
destroy: () => {
|
|
18550
|
+
document?.removeEventListener("mousedown", clickHandler);
|
|
18551
|
+
}
|
|
18552
|
+
};
|
|
18553
|
+
},
|
|
17550
18554
|
props: {
|
|
17551
18555
|
handleDOMEvents: {
|
|
17552
18556
|
contextmenu: (view, event) => {
|
|
@@ -17560,7 +18564,8 @@ const CustomSelection = Extension.create({
|
|
|
17560
18564
|
setFocusMeta(view.state.tr, {
|
|
17561
18565
|
focused: true,
|
|
17562
18566
|
preservedSelection: selection,
|
|
17563
|
-
showVisualSelection: true
|
|
18567
|
+
showVisualSelection: true,
|
|
18568
|
+
skipFocusReset: true
|
|
17564
18569
|
})
|
|
17565
18570
|
);
|
|
17566
18571
|
}
|
|
@@ -17581,7 +18586,8 @@ const CustomSelection = Extension.create({
|
|
|
17581
18586
|
setFocusMeta(view.state.tr, {
|
|
17582
18587
|
focused: true,
|
|
17583
18588
|
preservedSelection: selection2,
|
|
17584
|
-
showVisualSelection: true
|
|
18589
|
+
showVisualSelection: true,
|
|
18590
|
+
skipFocusReset: true
|
|
17585
18591
|
})
|
|
17586
18592
|
);
|
|
17587
18593
|
this.editor.setOptions({
|
|
@@ -17604,7 +18610,8 @@ const CustomSelection = Extension.create({
|
|
|
17604
18610
|
setFocusMeta(view.state.tr, {
|
|
17605
18611
|
focused: true,
|
|
17606
18612
|
preservedSelection: selection,
|
|
17607
|
-
showVisualSelection: true
|
|
18613
|
+
showVisualSelection: true,
|
|
18614
|
+
skipFocusReset: false
|
|
17608
18615
|
})
|
|
17609
18616
|
);
|
|
17610
18617
|
this.editor.setOptions({
|
|
@@ -17622,7 +18629,8 @@ const CustomSelection = Extension.create({
|
|
|
17622
18629
|
setFocusMeta(view.state.tr, {
|
|
17623
18630
|
focused: true,
|
|
17624
18631
|
preservedSelection: selection,
|
|
17625
|
-
showVisualSelection: true
|
|
18632
|
+
showVisualSelection: true,
|
|
18633
|
+
skipFocusReset: false
|
|
17626
18634
|
})
|
|
17627
18635
|
);
|
|
17628
18636
|
}
|
|
@@ -17633,7 +18641,8 @@ const CustomSelection = Extension.create({
|
|
|
17633
18641
|
setFocusMeta(view.state.tr, {
|
|
17634
18642
|
focused: false,
|
|
17635
18643
|
preservedSelection: null,
|
|
17636
|
-
showVisualSelection: false
|
|
18644
|
+
showVisualSelection: false,
|
|
18645
|
+
skipFocusReset: false
|
|
17637
18646
|
})
|
|
17638
18647
|
);
|
|
17639
18648
|
if (!selection.empty && !this.editor.options.element?.contains(target)) {
|
|
@@ -17650,12 +18659,20 @@ const CustomSelection = Extension.create({
|
|
|
17650
18659
|
const isElement2 = target instanceof Element;
|
|
17651
18660
|
const isToolbarBtn = isElement2 && isToolbarButton(target);
|
|
17652
18661
|
const isToolbarInp = isElement2 && isToolbarInput(target);
|
|
18662
|
+
const focusState = getFocusState(view.state);
|
|
18663
|
+
if (focusState?.skipFocusReset) {
|
|
18664
|
+
view.dispatch(
|
|
18665
|
+
setFocusMeta(view.state.tr, normalizeSelectionState({ ...focusState, skipFocusReset: false }))
|
|
18666
|
+
);
|
|
18667
|
+
return false;
|
|
18668
|
+
}
|
|
17653
18669
|
if (!isToolbarBtn && !isToolbarInp) {
|
|
17654
18670
|
view.dispatch(
|
|
17655
18671
|
setFocusMeta(view.state.tr, {
|
|
17656
18672
|
focused: false,
|
|
17657
18673
|
preservedSelection: null,
|
|
17658
|
-
showVisualSelection: false
|
|
18674
|
+
showVisualSelection: false,
|
|
18675
|
+
skipFocusReset: false
|
|
17659
18676
|
})
|
|
17660
18677
|
);
|
|
17661
18678
|
}
|
|
@@ -17666,12 +18683,16 @@ const CustomSelection = Extension.create({
|
|
|
17666
18683
|
const isToolbarBtn = isElement2 && isToolbarButton(target);
|
|
17667
18684
|
const isToolbarInp = isElement2 && isToolbarInput(target);
|
|
17668
18685
|
const state = getFocusState(view.state);
|
|
18686
|
+
if (state?.skipFocusReset) {
|
|
18687
|
+
return false;
|
|
18688
|
+
}
|
|
17669
18689
|
if (isToolbarBtn || isToolbarInp) {
|
|
17670
18690
|
view.dispatch(
|
|
17671
18691
|
setFocusMeta(view.state.tr, {
|
|
17672
18692
|
focused: true,
|
|
17673
18693
|
preservedSelection: state.preservedSelection || view.state.selection,
|
|
17674
|
-
showVisualSelection: true
|
|
18694
|
+
showVisualSelection: true,
|
|
18695
|
+
skipFocusReset: false
|
|
17675
18696
|
})
|
|
17676
18697
|
);
|
|
17677
18698
|
} else {
|
|
@@ -17679,7 +18700,8 @@ const CustomSelection = Extension.create({
|
|
|
17679
18700
|
setFocusMeta(view.state.tr, {
|
|
17680
18701
|
focused: false,
|
|
17681
18702
|
preservedSelection: null,
|
|
17682
|
-
showVisualSelection: false
|
|
18703
|
+
showVisualSelection: false,
|
|
18704
|
+
skipFocusReset: false
|
|
17683
18705
|
})
|
|
17684
18706
|
);
|
|
17685
18707
|
}
|
|
@@ -18525,7 +19547,7 @@ class ListItemNodeView {
|
|
|
18525
19547
|
this.decorations = decorations;
|
|
18526
19548
|
this.view = editor.view;
|
|
18527
19549
|
this.getPos = getPos;
|
|
18528
|
-
__privateMethod(this, _ListItemNodeView_instances,
|
|
19550
|
+
__privateMethod(this, _ListItemNodeView_instances, init_fn3).call(this);
|
|
18529
19551
|
activeListItemNodeViews.add(this);
|
|
18530
19552
|
}
|
|
18531
19553
|
refreshIndentStyling() {
|
|
@@ -18586,7 +19608,7 @@ class ListItemNodeView {
|
|
|
18586
19608
|
}
|
|
18587
19609
|
}
|
|
18588
19610
|
_ListItemNodeView_instances = new WeakSet();
|
|
18589
|
-
|
|
19611
|
+
init_fn3 = function() {
|
|
18590
19612
|
const { attrs } = this.node;
|
|
18591
19613
|
const { listLevel, listNumberingType, lvlText, numId, level, customFormat } = attrs;
|
|
18592
19614
|
let orderMarker = "";
|
|
@@ -25695,984 +26717,335 @@ const PageNumber = Node$1.create({
|
|
|
25695
26717
|
}
|
|
25696
26718
|
};
|
|
25697
26719
|
},
|
|
25698
|
-
addAttributes() {
|
|
25699
|
-
return {
|
|
25700
|
-
marksAsAttrs: {
|
|
25701
|
-
default: null,
|
|
25702
|
-
rendered: false
|
|
25703
|
-
}
|
|
25704
|
-
};
|
|
25705
|
-
},
|
|
25706
|
-
addNodeView() {
|
|
25707
|
-
return ({ node, editor, getPos, decorations }) => {
|
|
25708
|
-
const htmlAttributes = this.options.htmlAttributes;
|
|
25709
|
-
return new AutoPageNumberNodeView(node, getPos, decorations, editor, htmlAttributes);
|
|
25710
|
-
};
|
|
25711
|
-
},
|
|
25712
|
-
parseDOM() {
|
|
25713
|
-
return [{ tag: 'span[data-id="auto-page-number"' }];
|
|
25714
|
-
},
|
|
25715
|
-
renderDOM({ htmlAttributes }) {
|
|
25716
|
-
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes)];
|
|
25717
|
-
},
|
|
25718
|
-
addCommands() {
|
|
25719
|
-
return {
|
|
25720
|
-
/**
|
|
25721
|
-
* Insert an automatic page number
|
|
25722
|
-
* @category Command
|
|
25723
|
-
* @returns {Function} Command function
|
|
25724
|
-
* @example
|
|
25725
|
-
* editor.commands.addAutoPageNumber()
|
|
25726
|
-
* @note Only works in header/footer contexts
|
|
25727
|
-
*/
|
|
25728
|
-
addAutoPageNumber: () => ({ tr, dispatch, state, editor }) => {
|
|
25729
|
-
const { options } = editor;
|
|
25730
|
-
if (!options.isHeaderOrFooter) return false;
|
|
25731
|
-
const { schema } = state;
|
|
25732
|
-
const pageNumberType = schema?.nodes?.["page-number"];
|
|
25733
|
-
if (!pageNumberType) return false;
|
|
25734
|
-
const pageNumberNodeJSON = { type: "page-number" };
|
|
25735
|
-
const pageNumberNode = schema.nodeFromJSON(pageNumberNodeJSON);
|
|
25736
|
-
if (dispatch) {
|
|
25737
|
-
tr.replaceSelectionWith(pageNumberNode, false);
|
|
25738
|
-
tr.setMeta("forceUpdatePagination", true);
|
|
25739
|
-
}
|
|
25740
|
-
return true;
|
|
25741
|
-
}
|
|
25742
|
-
};
|
|
25743
|
-
},
|
|
25744
|
-
addShortcuts() {
|
|
25745
|
-
return {
|
|
25746
|
-
"Mod-Shift-alt-p": () => this.editor.commands.addAutoPageNumber()
|
|
25747
|
-
};
|
|
25748
|
-
}
|
|
25749
|
-
});
|
|
25750
|
-
const TotalPageCount = Node$1.create({
|
|
25751
|
-
name: "total-page-number",
|
|
25752
|
-
group: "inline",
|
|
25753
|
-
inline: true,
|
|
25754
|
-
atom: true,
|
|
25755
|
-
draggable: false,
|
|
25756
|
-
selectable: false,
|
|
25757
|
-
content: "text*",
|
|
25758
|
-
addOptions() {
|
|
25759
|
-
return {
|
|
25760
|
-
htmlAttributes: {
|
|
25761
|
-
contenteditable: false,
|
|
25762
|
-
"data-id": "auto-total-pages",
|
|
25763
|
-
"aria-label": "Total page count node",
|
|
25764
|
-
class: "sd-editor-auto-total-pages"
|
|
25765
|
-
}
|
|
25766
|
-
};
|
|
25767
|
-
},
|
|
25768
|
-
addAttributes() {
|
|
25769
|
-
return {
|
|
25770
|
-
marksAsAttrs: {
|
|
25771
|
-
default: null,
|
|
25772
|
-
rendered: false
|
|
25773
|
-
}
|
|
25774
|
-
};
|
|
25775
|
-
},
|
|
25776
|
-
addNodeView() {
|
|
25777
|
-
return ({ node, editor, getPos, decorations }) => {
|
|
25778
|
-
const htmlAttributes = this.options.htmlAttributes;
|
|
25779
|
-
return new AutoPageNumberNodeView(node, getPos, decorations, editor, htmlAttributes);
|
|
25780
|
-
};
|
|
25781
|
-
},
|
|
25782
|
-
parseDOM() {
|
|
25783
|
-
return [{ tag: 'span[data-id="auto-total-pages"' }];
|
|
25784
|
-
},
|
|
25785
|
-
renderDOM({ htmlAttributes }) {
|
|
25786
|
-
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
25787
|
-
},
|
|
25788
|
-
addCommands() {
|
|
25789
|
-
return {
|
|
25790
|
-
/**
|
|
25791
|
-
* Insert total page count
|
|
25792
|
-
* @category Command
|
|
25793
|
-
* @returns {Function} Command function
|
|
25794
|
-
* @example
|
|
25795
|
-
* editor.commands.addTotalPageCount()
|
|
25796
|
-
* @note Only works in header/footer contexts
|
|
25797
|
-
*/
|
|
25798
|
-
addTotalPageCount: () => ({ tr, dispatch, state, editor }) => {
|
|
25799
|
-
const { options } = editor;
|
|
25800
|
-
if (!options.isHeaderOrFooter) return false;
|
|
25801
|
-
const { schema } = state;
|
|
25802
|
-
const pageNumberType = schema.nodes?.["total-page-number"];
|
|
25803
|
-
if (!pageNumberType) return false;
|
|
25804
|
-
const currentPages = editor?.options?.parentEditor?.currentTotalPages || 1;
|
|
25805
|
-
const pageNumberNode = {
|
|
25806
|
-
type: "total-page-number",
|
|
25807
|
-
content: [{ type: "text", text: String(currentPages) }]
|
|
25808
|
-
};
|
|
25809
|
-
const pageNode = schema.nodeFromJSON(pageNumberNode);
|
|
25810
|
-
if (dispatch) {
|
|
25811
|
-
tr.replaceSelectionWith(pageNode, false);
|
|
25812
|
-
}
|
|
25813
|
-
return true;
|
|
25814
|
-
}
|
|
25815
|
-
};
|
|
25816
|
-
},
|
|
25817
|
-
addShortcuts() {
|
|
25818
|
-
return {
|
|
25819
|
-
"Mod-Shift-alt-c": () => this.editor.commands.addTotalPageCount()
|
|
25820
|
-
};
|
|
25821
|
-
}
|
|
25822
|
-
});
|
|
25823
|
-
const getNodeAttributes = (nodeName, editor) => {
|
|
25824
|
-
switch (nodeName) {
|
|
25825
|
-
case "page-number":
|
|
25826
|
-
return {
|
|
25827
|
-
text: editor.options.currentPageNumber || "1",
|
|
25828
|
-
className: "sd-editor-auto-page-number",
|
|
25829
|
-
dataId: "auto-page-number",
|
|
25830
|
-
ariaLabel: "Page number node"
|
|
25831
|
-
};
|
|
25832
|
-
case "total-page-number":
|
|
25833
|
-
return {
|
|
25834
|
-
text: editor.options.parentEditor?.currentTotalPages || "1",
|
|
25835
|
-
className: "sd-editor-auto-total-pages",
|
|
25836
|
-
dataId: "auto-total-pages",
|
|
25837
|
-
ariaLabel: "Total page count node"
|
|
25838
|
-
};
|
|
25839
|
-
default:
|
|
25840
|
-
return {};
|
|
25841
|
-
}
|
|
25842
|
-
};
|
|
25843
|
-
class AutoPageNumberNodeView {
|
|
25844
|
-
constructor(node, getPos, decorations, editor, htmlAttributes = {}) {
|
|
25845
|
-
__privateAdd(this, _AutoPageNumberNodeView_instances);
|
|
25846
|
-
this.node = node;
|
|
25847
|
-
this.editor = editor;
|
|
25848
|
-
this.view = editor.view;
|
|
25849
|
-
this.getPos = getPos;
|
|
25850
|
-
this.editor = editor;
|
|
25851
|
-
this.dom = __privateMethod(this, _AutoPageNumberNodeView_instances, renderDom_fn).call(this, node, htmlAttributes);
|
|
25852
|
-
}
|
|
25853
|
-
update(node) {
|
|
25854
|
-
const incomingType = node?.type?.name;
|
|
25855
|
-
const currentType = this.node?.type?.name;
|
|
25856
|
-
if (!incomingType || incomingType !== currentType) return false;
|
|
25857
|
-
this.node = node;
|
|
25858
|
-
return true;
|
|
25859
|
-
}
|
|
25860
|
-
}
|
|
25861
|
-
_AutoPageNumberNodeView_instances = new WeakSet();
|
|
25862
|
-
renderDom_fn = function(node, htmlAttributes) {
|
|
25863
|
-
const attrs = getNodeAttributes(this.node.type.name, this.editor);
|
|
25864
|
-
const content = document.createTextNode(String(attrs.text));
|
|
25865
|
-
const nodeContent = document.createElement("span");
|
|
25866
|
-
nodeContent.className = attrs.className;
|
|
25867
|
-
nodeContent.setAttribute("data-id", attrs.dataId);
|
|
25868
|
-
nodeContent.setAttribute("aria-label", attrs.ariaLabel);
|
|
25869
|
-
const currentPos = this.getPos();
|
|
25870
|
-
const { styles, marks } = getMarksFromNeighbors(currentPos, this.view);
|
|
25871
|
-
__privateMethod(this, _AutoPageNumberNodeView_instances, scheduleUpdateNodeStyle_fn).call(this, currentPos, marks);
|
|
25872
|
-
Object.assign(nodeContent.style, styles);
|
|
25873
|
-
nodeContent.appendChild(content);
|
|
25874
|
-
Object.entries(htmlAttributes).forEach(([key2, value]) => {
|
|
25875
|
-
if (value) nodeContent.setAttribute(key2, value);
|
|
25876
|
-
});
|
|
25877
|
-
return nodeContent;
|
|
25878
|
-
};
|
|
25879
|
-
scheduleUpdateNodeStyle_fn = function(pos, marks) {
|
|
25880
|
-
setTimeout(() => {
|
|
25881
|
-
const { state } = this.editor;
|
|
25882
|
-
const { dispatch } = this.view;
|
|
25883
|
-
const node = state.doc.nodeAt(pos);
|
|
25884
|
-
if (!node || node.isText) return;
|
|
25885
|
-
const currentMarks = node.attrs.marksAsAttrs || [];
|
|
25886
|
-
const newMarks = marks.map((m) => ({ type: m.type.name, attrs: m.attrs }));
|
|
25887
|
-
const isEqual = JSON.stringify(currentMarks) === JSON.stringify(newMarks);
|
|
25888
|
-
if (isEqual) return;
|
|
25889
|
-
const newAttrs = {
|
|
25890
|
-
...node.attrs,
|
|
25891
|
-
marksAsAttrs: newMarks
|
|
25892
|
-
};
|
|
25893
|
-
const tr = state.tr.setNodeMarkup(pos, void 0, newAttrs);
|
|
25894
|
-
dispatch(tr);
|
|
25895
|
-
}, 0);
|
|
25896
|
-
};
|
|
25897
|
-
const getMarksFromNeighbors = (currentPos, view) => {
|
|
25898
|
-
const $pos = view.state.doc.resolve(currentPos);
|
|
25899
|
-
const styles = {};
|
|
25900
|
-
const marks = [];
|
|
25901
|
-
const before = $pos.nodeBefore;
|
|
25902
|
-
if (before) {
|
|
25903
|
-
Object.assign(styles, processMarks(before.marks));
|
|
25904
|
-
marks.push(...before.marks);
|
|
25905
|
-
}
|
|
25906
|
-
const after = $pos.nodeAfter;
|
|
25907
|
-
if (after) {
|
|
25908
|
-
Object.assign(styles, { ...styles, ...processMarks(after.marks) });
|
|
25909
|
-
marks.push(...after.marks);
|
|
25910
|
-
}
|
|
25911
|
-
return {
|
|
25912
|
-
styles,
|
|
25913
|
-
marks
|
|
25914
|
-
};
|
|
25915
|
-
};
|
|
25916
|
-
const processMarks = (marks) => {
|
|
25917
|
-
const styles = {};
|
|
25918
|
-
marks.forEach((mark) => {
|
|
25919
|
-
const { type, attrs } = mark;
|
|
25920
|
-
switch (type.name) {
|
|
25921
|
-
case "textStyle":
|
|
25922
|
-
if (attrs.fontFamily) styles["font-family"] = attrs.fontFamily;
|
|
25923
|
-
if (attrs.fontSize) styles["font-size"] = attrs.fontSize;
|
|
25924
|
-
if (attrs.color) styles["color"] = attrs.color;
|
|
25925
|
-
if (attrs.backgroundColor) styles["background-color"] = attrs.backgroundColor;
|
|
25926
|
-
break;
|
|
25927
|
-
case "bold":
|
|
25928
|
-
styles["font-weight"] = "bold";
|
|
25929
|
-
break;
|
|
25930
|
-
case "italic":
|
|
25931
|
-
styles["font-style"] = "italic";
|
|
25932
|
-
break;
|
|
25933
|
-
case "underline":
|
|
25934
|
-
styles["text-decoration"] = (styles["text-decoration"] || "") + " underline";
|
|
25935
|
-
break;
|
|
25936
|
-
case "strike":
|
|
25937
|
-
styles["text-decoration"] = (styles["text-decoration"] || "") + " line-through";
|
|
25938
|
-
break;
|
|
25939
|
-
default:
|
|
25940
|
-
if (attrs?.style) {
|
|
25941
|
-
Object.entries(attrs.style).forEach(([key2, value]) => {
|
|
25942
|
-
styles[key2] = value;
|
|
25943
|
-
});
|
|
25944
|
-
}
|
|
25945
|
-
break;
|
|
25946
|
-
}
|
|
25947
|
-
});
|
|
25948
|
-
return styles;
|
|
25949
|
-
};
|
|
25950
|
-
const ShapeContainer = Node$1.create({
|
|
25951
|
-
name: "shapeContainer",
|
|
25952
|
-
group: "block",
|
|
25953
|
-
content: "block+",
|
|
25954
|
-
isolating: true,
|
|
25955
|
-
addOptions() {
|
|
25956
|
-
return {
|
|
25957
|
-
htmlAttributes: {
|
|
25958
|
-
class: "sd-editor-shape-container",
|
|
25959
|
-
"aria-label": "Shape container node"
|
|
25960
|
-
}
|
|
25961
|
-
};
|
|
25962
|
-
},
|
|
25963
|
-
addAttributes() {
|
|
25964
|
-
return {
|
|
25965
|
-
fillcolor: {
|
|
25966
|
-
renderDOM: (attrs) => {
|
|
25967
|
-
if (!attrs.fillcolor) return {};
|
|
25968
|
-
return {
|
|
25969
|
-
style: `background-color: ${attrs.fillcolor}`
|
|
25970
|
-
};
|
|
25971
|
-
}
|
|
25972
|
-
},
|
|
25973
|
-
sdBlockId: {
|
|
25974
|
-
default: null,
|
|
25975
|
-
keepOnSplit: false,
|
|
25976
|
-
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
25977
|
-
renderDOM: (attrs) => {
|
|
25978
|
-
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
25979
|
-
}
|
|
25980
|
-
},
|
|
25981
|
-
style: {
|
|
25982
|
-
renderDOM: (attrs) => {
|
|
25983
|
-
if (!attrs.style) return {};
|
|
25984
|
-
return {
|
|
25985
|
-
style: attrs.style
|
|
25986
|
-
};
|
|
25987
|
-
}
|
|
25988
|
-
},
|
|
25989
|
-
wrapAttributes: {
|
|
25990
|
-
rendered: false
|
|
25991
|
-
},
|
|
25992
|
-
attributes: {
|
|
25993
|
-
rendered: false
|
|
25994
|
-
}
|
|
25995
|
-
};
|
|
25996
|
-
},
|
|
25997
|
-
parseDOM() {
|
|
25998
|
-
return [
|
|
25999
|
-
{
|
|
26000
|
-
tag: `div[data-type="${this.name}"]`
|
|
26001
|
-
}
|
|
26002
|
-
];
|
|
26003
|
-
},
|
|
26004
|
-
renderDOM({ htmlAttributes }) {
|
|
26005
|
-
return [
|
|
26006
|
-
"div",
|
|
26007
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
26008
|
-
0
|
|
26009
|
-
];
|
|
26010
|
-
}
|
|
26011
|
-
});
|
|
26012
|
-
const ShapeTextbox = Node$1.create({
|
|
26013
|
-
name: "shapeTextbox",
|
|
26014
|
-
group: "block",
|
|
26015
|
-
content: "paragraph* block*",
|
|
26016
|
-
isolating: true,
|
|
26017
|
-
addOptions() {
|
|
26018
|
-
return {
|
|
26019
|
-
htmlAttributes: {
|
|
26020
|
-
class: "sd-editor-shape-textbox",
|
|
26021
|
-
"aria-label": "Shape textbox node"
|
|
26022
|
-
}
|
|
26023
|
-
};
|
|
26024
|
-
},
|
|
26025
|
-
addAttributes() {
|
|
26026
|
-
return {
|
|
26027
|
-
sdBlockId: {
|
|
26028
|
-
default: null,
|
|
26029
|
-
keepOnSplit: false,
|
|
26030
|
-
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
26031
|
-
renderDOM: (attrs) => {
|
|
26032
|
-
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
26033
|
-
}
|
|
26034
|
-
},
|
|
26035
|
-
attributes: {
|
|
26036
|
-
rendered: false
|
|
26037
|
-
}
|
|
26038
|
-
};
|
|
26039
|
-
},
|
|
26040
|
-
parseDOM() {
|
|
26041
|
-
return [
|
|
26042
|
-
{
|
|
26043
|
-
tag: `div[data-type="${this.name}"]`
|
|
26044
|
-
}
|
|
26045
|
-
];
|
|
26046
|
-
},
|
|
26047
|
-
renderDOM({ htmlAttributes }) {
|
|
26048
|
-
return [
|
|
26049
|
-
"div",
|
|
26050
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
26051
|
-
0
|
|
26052
|
-
];
|
|
26053
|
-
}
|
|
26054
|
-
});
|
|
26055
|
-
const ContentBlock = Node$1.create({
|
|
26056
|
-
name: "contentBlock",
|
|
26057
|
-
group: "inline",
|
|
26058
|
-
content: "",
|
|
26059
|
-
isolating: true,
|
|
26060
|
-
atom: true,
|
|
26061
|
-
inline: true,
|
|
26062
|
-
addOptions() {
|
|
26063
|
-
return {
|
|
26064
|
-
htmlAttributes: {
|
|
26065
|
-
contenteditable: false
|
|
26066
|
-
}
|
|
26067
|
-
};
|
|
26068
|
-
},
|
|
26069
|
-
addAttributes() {
|
|
26070
|
-
return {
|
|
26071
|
-
horizontalRule: {
|
|
26072
|
-
default: false,
|
|
26073
|
-
renderDOM: ({ horizontalRule }) => {
|
|
26074
|
-
if (!horizontalRule) return {};
|
|
26075
|
-
return { "data-horizontal-rule": "true" };
|
|
26076
|
-
}
|
|
26077
|
-
},
|
|
26078
|
-
size: {
|
|
26079
|
-
default: null,
|
|
26080
|
-
renderDOM: ({ size }) => {
|
|
26081
|
-
if (!size) return {};
|
|
26082
|
-
let style = "";
|
|
26083
|
-
if (size.top) style += `top: ${size.top}px; `;
|
|
26084
|
-
if (size.left) style += `left: ${size.left}px; `;
|
|
26085
|
-
if (size.width) style += `width: ${size.width.toString().endsWith("%") ? size.width : `${size.width}px`}; `;
|
|
26086
|
-
if (size.height)
|
|
26087
|
-
style += `height: ${size.height.toString().endsWith("%") ? size.height : `${size.height}px`}; `;
|
|
26088
|
-
return { style };
|
|
26089
|
-
}
|
|
26090
|
-
},
|
|
26091
|
-
background: {
|
|
26092
|
-
default: null,
|
|
26093
|
-
renderDOM: (attrs) => {
|
|
26094
|
-
if (!attrs.background) return {};
|
|
26095
|
-
return {
|
|
26096
|
-
style: `background-color: ${attrs.background}`
|
|
26097
|
-
};
|
|
26098
|
-
}
|
|
26099
|
-
},
|
|
26100
|
-
drawingContent: {
|
|
26101
|
-
rendered: false
|
|
26102
|
-
},
|
|
26103
|
-
attributes: {
|
|
26720
|
+
addAttributes() {
|
|
26721
|
+
return {
|
|
26722
|
+
marksAsAttrs: {
|
|
26723
|
+
default: null,
|
|
26104
26724
|
rendered: false
|
|
26105
26725
|
}
|
|
26106
26726
|
};
|
|
26107
26727
|
},
|
|
26728
|
+
addNodeView() {
|
|
26729
|
+
return ({ node, editor, getPos, decorations }) => {
|
|
26730
|
+
const htmlAttributes = this.options.htmlAttributes;
|
|
26731
|
+
return new AutoPageNumberNodeView(node, getPos, decorations, editor, htmlAttributes);
|
|
26732
|
+
};
|
|
26733
|
+
},
|
|
26108
26734
|
parseDOM() {
|
|
26109
|
-
return [
|
|
26110
|
-
{
|
|
26111
|
-
tag: `div[data-type="${this.name}"]`
|
|
26112
|
-
}
|
|
26113
|
-
];
|
|
26735
|
+
return [{ tag: 'span[data-id="auto-page-number"' }];
|
|
26114
26736
|
},
|
|
26115
26737
|
renderDOM({ htmlAttributes }) {
|
|
26116
|
-
return ["
|
|
26738
|
+
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes)];
|
|
26117
26739
|
},
|
|
26118
26740
|
addCommands() {
|
|
26119
26741
|
return {
|
|
26120
26742
|
/**
|
|
26121
|
-
* Insert
|
|
26122
|
-
* @category Command
|
|
26123
|
-
* @example
|
|
26124
|
-
* editor.commands.insertHorizontalRule()
|
|
26125
|
-
* @note Creates a visual separator between content sections
|
|
26126
|
-
*/
|
|
26127
|
-
insertHorizontalRule: () => ({ commands: commands2 }) => {
|
|
26128
|
-
return commands2.insertContent({
|
|
26129
|
-
type: this.name,
|
|
26130
|
-
attrs: {
|
|
26131
|
-
horizontalRule: true,
|
|
26132
|
-
size: { width: "100%", height: 2 },
|
|
26133
|
-
background: "#e5e7eb"
|
|
26134
|
-
}
|
|
26135
|
-
});
|
|
26136
|
-
},
|
|
26137
|
-
/**
|
|
26138
|
-
* Insert a content block
|
|
26743
|
+
* Insert an automatic page number
|
|
26139
26744
|
* @category Command
|
|
26140
|
-
* @
|
|
26141
|
-
* @example
|
|
26142
|
-
* // Insert a spacer block
|
|
26143
|
-
* editor.commands.insertContentBlock({ size: { height: 20 } })
|
|
26144
|
-
*
|
|
26745
|
+
* @returns {Function} Command function
|
|
26145
26746
|
* @example
|
|
26146
|
-
*
|
|
26147
|
-
*
|
|
26148
|
-
* size: { width: '50%', height: 3 },
|
|
26149
|
-
* background: '#3b82f6'
|
|
26150
|
-
* })
|
|
26151
|
-
* @note Used for spacing, dividers, and special inline content
|
|
26747
|
+
* editor.commands.addAutoPageNumber()
|
|
26748
|
+
* @note Only works in header/footer contexts
|
|
26152
26749
|
*/
|
|
26153
|
-
|
|
26154
|
-
|
|
26155
|
-
|
|
26156
|
-
|
|
26157
|
-
|
|
26750
|
+
addAutoPageNumber: () => ({ tr, dispatch, state, editor }) => {
|
|
26751
|
+
const { options } = editor;
|
|
26752
|
+
if (!options.isHeaderOrFooter) return false;
|
|
26753
|
+
const { schema } = state;
|
|
26754
|
+
const pageNumberType = schema?.nodes?.["page-number"];
|
|
26755
|
+
if (!pageNumberType) return false;
|
|
26756
|
+
const pageNumberNodeJSON = { type: "page-number" };
|
|
26757
|
+
const pageNumberNode = schema.nodeFromJSON(pageNumberNodeJSON);
|
|
26758
|
+
if (dispatch) {
|
|
26759
|
+
tr.replaceSelectionWith(pageNumberNode, false);
|
|
26760
|
+
tr.setMeta("forceUpdatePagination", true);
|
|
26761
|
+
}
|
|
26762
|
+
return true;
|
|
26158
26763
|
}
|
|
26159
26764
|
};
|
|
26765
|
+
},
|
|
26766
|
+
addShortcuts() {
|
|
26767
|
+
return {
|
|
26768
|
+
"Mod-Shift-alt-p": () => this.editor.commands.addAutoPageNumber()
|
|
26769
|
+
};
|
|
26160
26770
|
}
|
|
26161
26771
|
});
|
|
26162
|
-
|
|
26163
|
-
|
|
26164
|
-
|
|
26165
|
-
__publicField(this, "view");
|
|
26166
|
-
__publicField(this, "getPos");
|
|
26167
|
-
__publicField(this, "decorations");
|
|
26168
|
-
__publicField(this, "innerDecorations");
|
|
26169
|
-
__publicField(this, "editor");
|
|
26170
|
-
__publicField(this, "extension");
|
|
26171
|
-
__publicField(this, "htmlAttributes");
|
|
26172
|
-
__publicField(this, "root");
|
|
26173
|
-
__publicField(this, "isDragging", false);
|
|
26174
|
-
this.node = props.node;
|
|
26175
|
-
this.view = props.editor.view;
|
|
26176
|
-
this.getPos = props.getPos;
|
|
26177
|
-
this.decorations = props.decorations;
|
|
26178
|
-
this.innerDecorations = props.innerDecorations;
|
|
26179
|
-
this.editor = props.editor;
|
|
26180
|
-
this.extension = props.extension;
|
|
26181
|
-
this.htmlAttributes = props.htmlAttributes;
|
|
26182
|
-
this.mount(props);
|
|
26183
|
-
}
|
|
26184
|
-
mount() {
|
|
26185
|
-
return;
|
|
26186
|
-
}
|
|
26187
|
-
get dom() {
|
|
26188
|
-
return this.root;
|
|
26189
|
-
}
|
|
26190
|
-
get contentDOM() {
|
|
26191
|
-
return null;
|
|
26192
|
-
}
|
|
26193
|
-
update(node, decorations, innerDecorations) {
|
|
26194
|
-
if (node.type !== this.node.type) {
|
|
26195
|
-
return false;
|
|
26196
|
-
}
|
|
26197
|
-
this.node = node;
|
|
26198
|
-
this.decorations = decorations;
|
|
26199
|
-
this.innerDecorations = innerDecorations;
|
|
26200
|
-
this.updateHTMLAttributes();
|
|
26201
|
-
return true;
|
|
26202
|
-
}
|
|
26203
|
-
stopEvent(event) {
|
|
26204
|
-
if (!this.dom) return false;
|
|
26205
|
-
const target = event.target;
|
|
26206
|
-
const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
|
|
26207
|
-
if (!isInElement) return false;
|
|
26208
|
-
const isDragEvent = event.type.startsWith("drag");
|
|
26209
|
-
const isDropEvent = event.type === "drop";
|
|
26210
|
-
const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
|
|
26211
|
-
if (isInput && !isDropEvent && !isDragEvent) return true;
|
|
26212
|
-
const { isEditable } = this.editor;
|
|
26213
|
-
const { isDragging } = this;
|
|
26214
|
-
const isDraggable = !!this.node.type.spec.draggable;
|
|
26215
|
-
const isSelectable = NodeSelection.isSelectable(this.node);
|
|
26216
|
-
const isCopyEvent = event.type === "copy";
|
|
26217
|
-
const isPasteEvent = event.type === "paste";
|
|
26218
|
-
const isCutEvent = event.type === "cut";
|
|
26219
|
-
const isClickEvent = event.type === "mousedown";
|
|
26220
|
-
if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
|
|
26221
|
-
event.preventDefault();
|
|
26222
|
-
}
|
|
26223
|
-
if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
|
|
26224
|
-
event.preventDefault();
|
|
26225
|
-
return false;
|
|
26226
|
-
}
|
|
26227
|
-
if (isDraggable && isEditable && !isDragging && isClickEvent) {
|
|
26228
|
-
const dragHandle = target.closest("[data-drag-handle]");
|
|
26229
|
-
const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
|
|
26230
|
-
if (isValidDragHandle) {
|
|
26231
|
-
this.isDragging = true;
|
|
26232
|
-
document.addEventListener(
|
|
26233
|
-
"dragend",
|
|
26234
|
-
() => {
|
|
26235
|
-
this.isDragging = false;
|
|
26236
|
-
},
|
|
26237
|
-
{ once: true }
|
|
26238
|
-
);
|
|
26239
|
-
document.addEventListener(
|
|
26240
|
-
"drop",
|
|
26241
|
-
() => {
|
|
26242
|
-
this.isDragging = false;
|
|
26243
|
-
},
|
|
26244
|
-
{ once: true }
|
|
26245
|
-
);
|
|
26246
|
-
document.addEventListener(
|
|
26247
|
-
"mouseup",
|
|
26248
|
-
() => {
|
|
26249
|
-
this.isDragging = false;
|
|
26250
|
-
},
|
|
26251
|
-
{ once: true }
|
|
26252
|
-
);
|
|
26253
|
-
}
|
|
26254
|
-
}
|
|
26255
|
-
if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
|
|
26256
|
-
return false;
|
|
26257
|
-
}
|
|
26258
|
-
return true;
|
|
26259
|
-
}
|
|
26260
|
-
ignoreMutation(mutation) {
|
|
26261
|
-
if (!this.dom || !this.contentDOM) return true;
|
|
26262
|
-
if (this.node.isLeaf || this.node.isAtom) return true;
|
|
26263
|
-
if (mutation.type === "selection") return false;
|
|
26264
|
-
if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
|
|
26265
|
-
if (this.contentDOM.contains(mutation.target)) return false;
|
|
26266
|
-
return true;
|
|
26267
|
-
}
|
|
26268
|
-
destroy() {
|
|
26269
|
-
this.dom.remove();
|
|
26270
|
-
this.contentDOM?.remove();
|
|
26271
|
-
}
|
|
26272
|
-
updateAttributes(attrs) {
|
|
26273
|
-
const pos = this.getPos();
|
|
26274
|
-
if (typeof pos !== "number") {
|
|
26275
|
-
return;
|
|
26276
|
-
}
|
|
26277
|
-
return this.view.dispatch(
|
|
26278
|
-
this.view.state.tr.setNodeMarkup(pos, void 0, {
|
|
26279
|
-
...this.node.attrs,
|
|
26280
|
-
...attrs
|
|
26281
|
-
})
|
|
26282
|
-
);
|
|
26283
|
-
}
|
|
26284
|
-
updateHTMLAttributes() {
|
|
26285
|
-
const { extensionService } = this.editor;
|
|
26286
|
-
const { attributes } = extensionService;
|
|
26287
|
-
const extensionAttrs = attributes.filter((i) => i.type === this.node.type.name);
|
|
26288
|
-
this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
|
|
26289
|
-
}
|
|
26290
|
-
createDragHandle() {
|
|
26291
|
-
const dragHandle = document.createElement("span");
|
|
26292
|
-
dragHandle.classList.add("sd-structured-content-draggable");
|
|
26293
|
-
dragHandle.draggable = true;
|
|
26294
|
-
dragHandle.contentEditable = "false";
|
|
26295
|
-
dragHandle.dataset.dragHandle = "";
|
|
26296
|
-
const textElement = document.createElement("span");
|
|
26297
|
-
textElement.textContent = "Structured content";
|
|
26298
|
-
dragHandle.append(textElement);
|
|
26299
|
-
return dragHandle;
|
|
26300
|
-
}
|
|
26301
|
-
onDragStart(event) {
|
|
26302
|
-
const { view } = this.editor;
|
|
26303
|
-
const target = event.target;
|
|
26304
|
-
const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
|
|
26305
|
-
if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
|
|
26306
|
-
return;
|
|
26307
|
-
}
|
|
26308
|
-
let x = 0;
|
|
26309
|
-
let y = 0;
|
|
26310
|
-
if (this.dom !== dragHandle) {
|
|
26311
|
-
const domBox = this.dom.getBoundingClientRect();
|
|
26312
|
-
const handleBox = dragHandle.getBoundingClientRect();
|
|
26313
|
-
const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
|
|
26314
|
-
const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
|
|
26315
|
-
x = handleBox.x - domBox.x + offsetX;
|
|
26316
|
-
y = handleBox.y - domBox.y + offsetY;
|
|
26317
|
-
}
|
|
26318
|
-
event.dataTransfer?.setDragImage(this.dom, x, y);
|
|
26319
|
-
const pos = this.getPos();
|
|
26320
|
-
if (typeof pos !== "number") {
|
|
26321
|
-
return;
|
|
26322
|
-
}
|
|
26323
|
-
const selection = NodeSelection.create(view.state.doc, pos);
|
|
26324
|
-
const transaction = view.state.tr.setSelection(selection);
|
|
26325
|
-
view.dispatch(transaction);
|
|
26326
|
-
}
|
|
26327
|
-
}
|
|
26328
|
-
class StructuredContentInlineView extends StructuredContentViewBase {
|
|
26329
|
-
constructor(props) {
|
|
26330
|
-
super(props);
|
|
26331
|
-
}
|
|
26332
|
-
mount() {
|
|
26333
|
-
this.buildView();
|
|
26334
|
-
}
|
|
26335
|
-
get contentDOM() {
|
|
26336
|
-
const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
|
|
26337
|
-
return contentElement || null;
|
|
26338
|
-
}
|
|
26339
|
-
createElement() {
|
|
26340
|
-
const element = document.createElement("span");
|
|
26341
|
-
element.classList.add(structuredContentClass$1);
|
|
26342
|
-
element.setAttribute("data-structured-content", "");
|
|
26343
|
-
const contentElement = document.createElement("span");
|
|
26344
|
-
contentElement.classList.add(structuredContentInnerClass$1);
|
|
26345
|
-
element.append(contentElement);
|
|
26346
|
-
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
26347
|
-
updateDOMAttributes(element, { ...domAttrs });
|
|
26348
|
-
return { element, contentElement };
|
|
26349
|
-
}
|
|
26350
|
-
buildView() {
|
|
26351
|
-
const { element } = this.createElement();
|
|
26352
|
-
const dragHandle = this.createDragHandle();
|
|
26353
|
-
element.prepend(dragHandle);
|
|
26354
|
-
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
26355
|
-
this.root = element;
|
|
26356
|
-
}
|
|
26357
|
-
updateView() {
|
|
26358
|
-
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
26359
|
-
updateDOMAttributes(this.dom, { ...domAttrs });
|
|
26360
|
-
}
|
|
26361
|
-
update(node, decorations, innerDecorations) {
|
|
26362
|
-
const result = super.update(node, decorations, innerDecorations);
|
|
26363
|
-
if (!result) return false;
|
|
26364
|
-
this.updateView();
|
|
26365
|
-
return true;
|
|
26366
|
-
}
|
|
26367
|
-
}
|
|
26368
|
-
const structuredContentClass$1 = "sd-structured-content";
|
|
26369
|
-
const structuredContentInnerClass$1 = "sd-structured-content__content";
|
|
26370
|
-
const StructuredContent = Node$1.create({
|
|
26371
|
-
name: "structuredContent",
|
|
26372
|
-
group: "inline structuredContent",
|
|
26772
|
+
const TotalPageCount = Node$1.create({
|
|
26773
|
+
name: "total-page-number",
|
|
26774
|
+
group: "inline",
|
|
26373
26775
|
inline: true,
|
|
26374
|
-
|
|
26375
|
-
|
|
26376
|
-
|
|
26377
|
-
|
|
26378
|
-
draggable: true,
|
|
26776
|
+
atom: true,
|
|
26777
|
+
draggable: false,
|
|
26778
|
+
selectable: false,
|
|
26779
|
+
content: "text*",
|
|
26379
26780
|
addOptions() {
|
|
26380
26781
|
return {
|
|
26381
26782
|
htmlAttributes: {
|
|
26382
|
-
|
|
26383
|
-
"
|
|
26783
|
+
contenteditable: false,
|
|
26784
|
+
"data-id": "auto-total-pages",
|
|
26785
|
+
"aria-label": "Total page count node",
|
|
26786
|
+
class: "sd-editor-auto-total-pages"
|
|
26384
26787
|
}
|
|
26385
26788
|
};
|
|
26386
26789
|
},
|
|
26387
26790
|
addAttributes() {
|
|
26388
26791
|
return {
|
|
26389
|
-
|
|
26792
|
+
marksAsAttrs: {
|
|
26390
26793
|
default: null,
|
|
26391
|
-
parseDOM: (elem) => elem.getAttribute("data-id"),
|
|
26392
|
-
renderDOM: (attrs) => {
|
|
26393
|
-
if (!attrs.id) return {};
|
|
26394
|
-
return { "data-id": attrs.id };
|
|
26395
|
-
}
|
|
26396
|
-
},
|
|
26397
|
-
sdtPr: {
|
|
26398
26794
|
rendered: false
|
|
26399
26795
|
}
|
|
26400
26796
|
};
|
|
26401
26797
|
},
|
|
26798
|
+
addNodeView() {
|
|
26799
|
+
return ({ node, editor, getPos, decorations }) => {
|
|
26800
|
+
const htmlAttributes = this.options.htmlAttributes;
|
|
26801
|
+
return new AutoPageNumberNodeView(node, getPos, decorations, editor, htmlAttributes);
|
|
26802
|
+
};
|
|
26803
|
+
},
|
|
26402
26804
|
parseDOM() {
|
|
26403
|
-
return [{ tag:
|
|
26805
|
+
return [{ tag: 'span[data-id="auto-total-pages"' }];
|
|
26404
26806
|
},
|
|
26405
26807
|
renderDOM({ htmlAttributes }) {
|
|
26406
|
-
return [
|
|
26407
|
-
"span",
|
|
26408
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
|
|
26409
|
-
"data-structured-content": ""
|
|
26410
|
-
}),
|
|
26411
|
-
0
|
|
26412
|
-
];
|
|
26808
|
+
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
26413
26809
|
},
|
|
26414
|
-
|
|
26415
|
-
return
|
|
26416
|
-
|
|
26810
|
+
addCommands() {
|
|
26811
|
+
return {
|
|
26812
|
+
/**
|
|
26813
|
+
* Insert total page count
|
|
26814
|
+
* @category Command
|
|
26815
|
+
* @returns {Function} Command function
|
|
26816
|
+
* @example
|
|
26817
|
+
* editor.commands.addTotalPageCount()
|
|
26818
|
+
* @note Only works in header/footer contexts
|
|
26819
|
+
*/
|
|
26820
|
+
addTotalPageCount: () => ({ tr, dispatch, state, editor }) => {
|
|
26821
|
+
const { options } = editor;
|
|
26822
|
+
if (!options.isHeaderOrFooter) return false;
|
|
26823
|
+
const { schema } = state;
|
|
26824
|
+
const pageNumberType = schema.nodes?.["total-page-number"];
|
|
26825
|
+
if (!pageNumberType) return false;
|
|
26826
|
+
const currentPages = editor?.options?.parentEditor?.currentTotalPages || 1;
|
|
26827
|
+
const pageNumberNode = {
|
|
26828
|
+
type: "total-page-number",
|
|
26829
|
+
content: [{ type: "text", text: String(currentPages) }]
|
|
26830
|
+
};
|
|
26831
|
+
const pageNode = schema.nodeFromJSON(pageNumberNode);
|
|
26832
|
+
if (dispatch) {
|
|
26833
|
+
tr.replaceSelectionWith(pageNode, false);
|
|
26834
|
+
}
|
|
26835
|
+
return true;
|
|
26836
|
+
}
|
|
26837
|
+
};
|
|
26838
|
+
},
|
|
26839
|
+
addShortcuts() {
|
|
26840
|
+
return {
|
|
26841
|
+
"Mod-Shift-alt-c": () => this.editor.commands.addTotalPageCount()
|
|
26417
26842
|
};
|
|
26418
26843
|
}
|
|
26419
26844
|
});
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
|
|
26423
|
-
|
|
26424
|
-
|
|
26425
|
-
|
|
26426
|
-
|
|
26427
|
-
|
|
26428
|
-
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26432
|
-
|
|
26433
|
-
|
|
26434
|
-
|
|
26435
|
-
|
|
26436
|
-
|
|
26437
|
-
|
|
26438
|
-
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
26439
|
-
updateDOMAttributes(element, { ...domAttrs });
|
|
26440
|
-
return { element, contentElement };
|
|
26441
|
-
}
|
|
26442
|
-
buildView() {
|
|
26443
|
-
const { element } = this.createElement();
|
|
26444
|
-
const dragHandle = this.createDragHandle();
|
|
26445
|
-
element.prepend(dragHandle);
|
|
26446
|
-
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
26447
|
-
this.root = element;
|
|
26845
|
+
const getNodeAttributes = (nodeName, editor) => {
|
|
26846
|
+
switch (nodeName) {
|
|
26847
|
+
case "page-number":
|
|
26848
|
+
return {
|
|
26849
|
+
text: editor.options.currentPageNumber || "1",
|
|
26850
|
+
className: "sd-editor-auto-page-number",
|
|
26851
|
+
dataId: "auto-page-number",
|
|
26852
|
+
ariaLabel: "Page number node"
|
|
26853
|
+
};
|
|
26854
|
+
case "total-page-number":
|
|
26855
|
+
return {
|
|
26856
|
+
text: editor.options.parentEditor?.currentTotalPages || "1",
|
|
26857
|
+
className: "sd-editor-auto-total-pages",
|
|
26858
|
+
dataId: "auto-total-pages",
|
|
26859
|
+
ariaLabel: "Total page count node"
|
|
26860
|
+
};
|
|
26861
|
+
default:
|
|
26862
|
+
return {};
|
|
26448
26863
|
}
|
|
26449
|
-
|
|
26450
|
-
|
|
26451
|
-
|
|
26864
|
+
};
|
|
26865
|
+
class AutoPageNumberNodeView {
|
|
26866
|
+
constructor(node, getPos, decorations, editor, htmlAttributes = {}) {
|
|
26867
|
+
__privateAdd(this, _AutoPageNumberNodeView_instances);
|
|
26868
|
+
this.node = node;
|
|
26869
|
+
this.editor = editor;
|
|
26870
|
+
this.view = editor.view;
|
|
26871
|
+
this.getPos = getPos;
|
|
26872
|
+
this.editor = editor;
|
|
26873
|
+
this.dom = __privateMethod(this, _AutoPageNumberNodeView_instances, renderDom_fn).call(this, node, htmlAttributes);
|
|
26452
26874
|
}
|
|
26453
|
-
update(node
|
|
26454
|
-
const
|
|
26455
|
-
|
|
26456
|
-
|
|
26875
|
+
update(node) {
|
|
26876
|
+
const incomingType = node?.type?.name;
|
|
26877
|
+
const currentType = this.node?.type?.name;
|
|
26878
|
+
if (!incomingType || incomingType !== currentType) return false;
|
|
26879
|
+
this.node = node;
|
|
26457
26880
|
return true;
|
|
26458
26881
|
}
|
|
26459
26882
|
}
|
|
26460
|
-
|
|
26461
|
-
|
|
26462
|
-
const
|
|
26463
|
-
|
|
26464
|
-
|
|
26465
|
-
|
|
26883
|
+
_AutoPageNumberNodeView_instances = new WeakSet();
|
|
26884
|
+
renderDom_fn = function(node, htmlAttributes) {
|
|
26885
|
+
const attrs = getNodeAttributes(this.node.type.name, this.editor);
|
|
26886
|
+
const content = document.createTextNode(String(attrs.text));
|
|
26887
|
+
const nodeContent = document.createElement("span");
|
|
26888
|
+
nodeContent.className = attrs.className;
|
|
26889
|
+
nodeContent.setAttribute("data-id", attrs.dataId);
|
|
26890
|
+
nodeContent.setAttribute("aria-label", attrs.ariaLabel);
|
|
26891
|
+
const currentPos = this.getPos();
|
|
26892
|
+
const { styles, marks } = getMarksFromNeighbors(currentPos, this.view);
|
|
26893
|
+
__privateMethod(this, _AutoPageNumberNodeView_instances, scheduleUpdateNodeStyle_fn).call(this, currentPos, marks);
|
|
26894
|
+
Object.assign(nodeContent.style, styles);
|
|
26895
|
+
nodeContent.appendChild(content);
|
|
26896
|
+
Object.entries(htmlAttributes).forEach(([key2, value]) => {
|
|
26897
|
+
if (value) nodeContent.setAttribute(key2, value);
|
|
26898
|
+
});
|
|
26899
|
+
return nodeContent;
|
|
26900
|
+
};
|
|
26901
|
+
scheduleUpdateNodeStyle_fn = function(pos, marks) {
|
|
26902
|
+
setTimeout(() => {
|
|
26903
|
+
const { state } = this.editor;
|
|
26904
|
+
const { dispatch } = this.view;
|
|
26905
|
+
const node = state.doc.nodeAt(pos);
|
|
26906
|
+
if (!node || node.isText) return;
|
|
26907
|
+
const currentMarks = node.attrs.marksAsAttrs || [];
|
|
26908
|
+
const newMarks = marks.map((m) => ({ type: m.type.name, attrs: m.attrs }));
|
|
26909
|
+
const isEqual = JSON.stringify(currentMarks) === JSON.stringify(newMarks);
|
|
26910
|
+
if (isEqual) return;
|
|
26911
|
+
const newAttrs = {
|
|
26912
|
+
...node.attrs,
|
|
26913
|
+
marksAsAttrs: newMarks
|
|
26914
|
+
};
|
|
26915
|
+
const tr = state.tr.setNodeMarkup(pos, void 0, newAttrs);
|
|
26916
|
+
dispatch(tr);
|
|
26917
|
+
}, 0);
|
|
26918
|
+
};
|
|
26919
|
+
const getMarksFromNeighbors = (currentPos, view) => {
|
|
26920
|
+
const $pos = view.state.doc.resolve(currentPos);
|
|
26921
|
+
const styles = {};
|
|
26922
|
+
const marks = [];
|
|
26923
|
+
const before = $pos.nodeBefore;
|
|
26924
|
+
if (before) {
|
|
26925
|
+
Object.assign(styles, processMarks(before.marks));
|
|
26926
|
+
marks.push(...before.marks);
|
|
26927
|
+
}
|
|
26928
|
+
const after = $pos.nodeAfter;
|
|
26929
|
+
if (after) {
|
|
26930
|
+
Object.assign(styles, { ...styles, ...processMarks(after.marks) });
|
|
26931
|
+
marks.push(...after.marks);
|
|
26932
|
+
}
|
|
26933
|
+
return {
|
|
26934
|
+
styles,
|
|
26935
|
+
marks
|
|
26936
|
+
};
|
|
26937
|
+
};
|
|
26938
|
+
const processMarks = (marks) => {
|
|
26939
|
+
const styles = {};
|
|
26940
|
+
marks.forEach((mark) => {
|
|
26941
|
+
const { type, attrs } = mark;
|
|
26942
|
+
switch (type.name) {
|
|
26943
|
+
case "textStyle":
|
|
26944
|
+
if (attrs.fontFamily) styles["font-family"] = attrs.fontFamily;
|
|
26945
|
+
if (attrs.fontSize) styles["font-size"] = attrs.fontSize;
|
|
26946
|
+
if (attrs.color) styles["color"] = attrs.color;
|
|
26947
|
+
if (attrs.backgroundColor) styles["background-color"] = attrs.backgroundColor;
|
|
26948
|
+
break;
|
|
26949
|
+
case "bold":
|
|
26950
|
+
styles["font-weight"] = "bold";
|
|
26951
|
+
break;
|
|
26952
|
+
case "italic":
|
|
26953
|
+
styles["font-style"] = "italic";
|
|
26954
|
+
break;
|
|
26955
|
+
case "underline":
|
|
26956
|
+
styles["text-decoration"] = (styles["text-decoration"] || "") + " underline";
|
|
26957
|
+
break;
|
|
26958
|
+
case "strike":
|
|
26959
|
+
styles["text-decoration"] = (styles["text-decoration"] || "") + " line-through";
|
|
26960
|
+
break;
|
|
26961
|
+
default:
|
|
26962
|
+
if (attrs?.style) {
|
|
26963
|
+
Object.entries(attrs.style).forEach(([key2, value]) => {
|
|
26964
|
+
styles[key2] = value;
|
|
26965
|
+
});
|
|
26966
|
+
}
|
|
26967
|
+
break;
|
|
26968
|
+
}
|
|
26969
|
+
});
|
|
26970
|
+
return styles;
|
|
26971
|
+
};
|
|
26972
|
+
const ShapeContainer = Node$1.create({
|
|
26973
|
+
name: "shapeContainer",
|
|
26974
|
+
group: "block",
|
|
26975
|
+
content: "block+",
|
|
26466
26976
|
isolating: true,
|
|
26467
|
-
atom: false,
|
|
26468
|
-
// false - has editable content.
|
|
26469
|
-
draggable: true,
|
|
26470
26977
|
addOptions() {
|
|
26471
26978
|
return {
|
|
26472
26979
|
htmlAttributes: {
|
|
26473
|
-
class:
|
|
26474
|
-
"aria-label": "
|
|
26980
|
+
class: "sd-editor-shape-container",
|
|
26981
|
+
"aria-label": "Shape container node"
|
|
26475
26982
|
}
|
|
26476
26983
|
};
|
|
26477
26984
|
},
|
|
26478
26985
|
addAttributes() {
|
|
26479
26986
|
return {
|
|
26480
|
-
|
|
26987
|
+
fillcolor: {
|
|
26988
|
+
renderDOM: (attrs) => {
|
|
26989
|
+
if (!attrs.fillcolor) return {};
|
|
26990
|
+
return {
|
|
26991
|
+
style: `background-color: ${attrs.fillcolor}`
|
|
26992
|
+
};
|
|
26993
|
+
}
|
|
26994
|
+
},
|
|
26995
|
+
sdBlockId: {
|
|
26481
26996
|
default: null,
|
|
26482
|
-
|
|
26997
|
+
keepOnSplit: false,
|
|
26998
|
+
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
26483
26999
|
renderDOM: (attrs) => {
|
|
26484
|
-
|
|
26485
|
-
return { "data-id": attrs.id };
|
|
27000
|
+
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
26486
27001
|
}
|
|
26487
27002
|
},
|
|
26488
|
-
|
|
27003
|
+
style: {
|
|
27004
|
+
renderDOM: (attrs) => {
|
|
27005
|
+
if (!attrs.style) return {};
|
|
27006
|
+
return {
|
|
27007
|
+
style: attrs.style
|
|
27008
|
+
};
|
|
27009
|
+
}
|
|
27010
|
+
},
|
|
27011
|
+
wrapAttributes: {
|
|
27012
|
+
rendered: false
|
|
27013
|
+
},
|
|
27014
|
+
attributes: {
|
|
26489
27015
|
rendered: false
|
|
26490
27016
|
}
|
|
26491
27017
|
};
|
|
26492
27018
|
},
|
|
26493
27019
|
parseDOM() {
|
|
26494
|
-
return [
|
|
27020
|
+
return [
|
|
27021
|
+
{
|
|
27022
|
+
tag: `div[data-type="${this.name}"]`
|
|
27023
|
+
}
|
|
27024
|
+
];
|
|
26495
27025
|
},
|
|
26496
27026
|
renderDOM({ htmlAttributes }) {
|
|
26497
27027
|
return [
|
|
26498
27028
|
"div",
|
|
26499
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
|
|
26500
|
-
"data-structured-content-block": ""
|
|
26501
|
-
}),
|
|
27029
|
+
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
26502
27030
|
0
|
|
26503
27031
|
];
|
|
26504
|
-
},
|
|
26505
|
-
addNodeView() {
|
|
26506
|
-
return (props) => {
|
|
26507
|
-
return new StructuredContentBlockView({ ...props });
|
|
26508
|
-
};
|
|
26509
27032
|
}
|
|
26510
27033
|
});
|
|
26511
|
-
|
|
26512
|
-
|
|
26513
|
-
__privateAdd(this, _DocumentSectionView_instances);
|
|
26514
|
-
this.node = node;
|
|
26515
|
-
this.editor = editor;
|
|
26516
|
-
this.decorations = decorations;
|
|
26517
|
-
this.view = editor.view;
|
|
26518
|
-
this.getPos = getPos;
|
|
26519
|
-
__privateMethod(this, _DocumentSectionView_instances, init_fn3).call(this);
|
|
26520
|
-
}
|
|
26521
|
-
}
|
|
26522
|
-
_DocumentSectionView_instances = new WeakSet();
|
|
26523
|
-
init_fn3 = function() {
|
|
26524
|
-
const { attrs } = this.node;
|
|
26525
|
-
const { id, title, description } = attrs;
|
|
26526
|
-
this.dom = document.createElement("div");
|
|
26527
|
-
this.dom.className = "sd-document-section-block";
|
|
26528
|
-
this.dom.setAttribute("data-id", id);
|
|
26529
|
-
this.dom.setAttribute("data-title", title);
|
|
26530
|
-
this.dom.setAttribute("data-description", description);
|
|
26531
|
-
this.dom.setAttribute("aria-label", "Document section");
|
|
26532
|
-
__privateMethod(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
|
|
26533
|
-
this.contentDOM = document.createElement("div");
|
|
26534
|
-
this.contentDOM.className = "sd-document-section-block-content";
|
|
26535
|
-
this.contentDOM.setAttribute("contenteditable", "true");
|
|
26536
|
-
this.dom.appendChild(this.contentDOM);
|
|
26537
|
-
};
|
|
26538
|
-
addToolTip_fn = function() {
|
|
26539
|
-
const { title } = this.node.attrs;
|
|
26540
|
-
this.infoDiv = document.createElement("div");
|
|
26541
|
-
this.infoDiv.className = "sd-document-section-block-info";
|
|
26542
|
-
const textSpan = document.createElement("span");
|
|
26543
|
-
textSpan.textContent = title || "Document section";
|
|
26544
|
-
this.infoDiv.appendChild(textSpan);
|
|
26545
|
-
this.infoDiv.setAttribute("contenteditable", "false");
|
|
26546
|
-
this.dom.appendChild(this.infoDiv);
|
|
26547
|
-
};
|
|
26548
|
-
const getAllSections = (editor) => {
|
|
26549
|
-
if (!editor) return [];
|
|
26550
|
-
const type = editor.schema.nodes.documentSection;
|
|
26551
|
-
if (!type) return [];
|
|
26552
|
-
const sections = [];
|
|
26553
|
-
const { state } = editor;
|
|
26554
|
-
state.doc.descendants((node, pos) => {
|
|
26555
|
-
if (node.type.name === type.name) {
|
|
26556
|
-
sections.push({ node, pos });
|
|
26557
|
-
}
|
|
26558
|
-
});
|
|
26559
|
-
return sections;
|
|
26560
|
-
};
|
|
26561
|
-
const exportSectionsToHTML = (editor) => {
|
|
26562
|
-
const sections = getAllSections(editor);
|
|
26563
|
-
const processedSections = /* @__PURE__ */ new Set();
|
|
26564
|
-
const result = [];
|
|
26565
|
-
sections.forEach(({ node }) => {
|
|
26566
|
-
const { attrs } = node;
|
|
26567
|
-
const { id, title, description } = attrs;
|
|
26568
|
-
if (processedSections.has(id)) return;
|
|
26569
|
-
processedSections.add(id);
|
|
26570
|
-
const html = getHTMLFromNode(node, editor);
|
|
26571
|
-
result.push({
|
|
26572
|
-
id,
|
|
26573
|
-
title,
|
|
26574
|
-
description,
|
|
26575
|
-
html
|
|
26576
|
-
});
|
|
26577
|
-
});
|
|
26578
|
-
return result;
|
|
26579
|
-
};
|
|
26580
|
-
const getHTMLFromNode = (node, editor) => {
|
|
26581
|
-
const tempDocument = document.implementation.createHTMLDocument();
|
|
26582
|
-
const container = tempDocument.createElement("div");
|
|
26583
|
-
const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
|
|
26584
|
-
container.appendChild(fragment);
|
|
26585
|
-
let html = container.innerHTML;
|
|
26586
|
-
return html;
|
|
26587
|
-
};
|
|
26588
|
-
const exportSectionsToJSON = (editor) => {
|
|
26589
|
-
const sections = getAllSections(editor);
|
|
26590
|
-
const processedSections = /* @__PURE__ */ new Set();
|
|
26591
|
-
const result = [];
|
|
26592
|
-
sections.forEach(({ node }) => {
|
|
26593
|
-
const { attrs } = node;
|
|
26594
|
-
const { id, title, description } = attrs;
|
|
26595
|
-
if (processedSections.has(id)) return;
|
|
26596
|
-
processedSections.add(id);
|
|
26597
|
-
result.push({
|
|
26598
|
-
id,
|
|
26599
|
-
title,
|
|
26600
|
-
description,
|
|
26601
|
-
content: node.toJSON()
|
|
26602
|
-
});
|
|
26603
|
-
});
|
|
26604
|
-
return result;
|
|
26605
|
-
};
|
|
26606
|
-
const getLinkedSectionEditor = (id, options, editor) => {
|
|
26607
|
-
const sections = getAllSections(editor);
|
|
26608
|
-
const section = sections.find((s) => s.node.attrs.id === id);
|
|
26609
|
-
if (!section) return null;
|
|
26610
|
-
const child = editor.createChildEditor({
|
|
26611
|
-
...options,
|
|
26612
|
-
onUpdate: ({ editor: childEditor, transaction }) => {
|
|
26613
|
-
const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
|
|
26614
|
-
if (isFromtLinkedParent) return;
|
|
26615
|
-
const updatedContent = childEditor.state.doc.content;
|
|
26616
|
-
const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
|
|
26617
|
-
if (!sectionNode) return;
|
|
26618
|
-
const { pos, node } = sectionNode;
|
|
26619
|
-
const newNode = node.type.create(node.attrs, updatedContent, node.marks);
|
|
26620
|
-
const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
|
26621
|
-
tr.setMeta("fromLinkedChild", true);
|
|
26622
|
-
editor.view.dispatch(tr);
|
|
26623
|
-
}
|
|
26624
|
-
});
|
|
26625
|
-
editor.on("update", ({ transaction }) => {
|
|
26626
|
-
const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
|
|
26627
|
-
if (isFromLinkedChild) return;
|
|
26628
|
-
const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
|
|
26629
|
-
if (!sectionNode) return;
|
|
26630
|
-
const sectionContent = sectionNode.node.content;
|
|
26631
|
-
const json = {
|
|
26632
|
-
type: "doc",
|
|
26633
|
-
content: sectionContent.content.map((node) => node.toJSON())
|
|
26634
|
-
};
|
|
26635
|
-
const childTr = child.state.tr;
|
|
26636
|
-
childTr.setMeta("fromLinkedParent", true);
|
|
26637
|
-
childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
|
|
26638
|
-
child.view.dispatch(childTr);
|
|
26639
|
-
});
|
|
26640
|
-
return child;
|
|
26641
|
-
};
|
|
26642
|
-
const SectionHelpers = {
|
|
26643
|
-
getAllSections,
|
|
26644
|
-
exportSectionsToHTML,
|
|
26645
|
-
exportSectionsToJSON,
|
|
26646
|
-
getLinkedSectionEditor
|
|
26647
|
-
};
|
|
26648
|
-
const DocumentSection = Node$1.create({
|
|
26649
|
-
name: "documentSection",
|
|
27034
|
+
const ShapeTextbox = Node$1.create({
|
|
27035
|
+
name: "shapeTextbox",
|
|
26650
27036
|
group: "block",
|
|
26651
|
-
content: "block*",
|
|
26652
|
-
atom: true,
|
|
27037
|
+
content: "paragraph* block*",
|
|
26653
27038
|
isolating: true,
|
|
26654
27039
|
addOptions() {
|
|
26655
27040
|
return {
|
|
26656
27041
|
htmlAttributes: {
|
|
26657
|
-
class: "sd-
|
|
26658
|
-
"aria-label": "
|
|
27042
|
+
class: "sd-editor-shape-textbox",
|
|
27043
|
+
"aria-label": "Shape textbox node"
|
|
26659
27044
|
}
|
|
26660
27045
|
};
|
|
26661
27046
|
},
|
|
26662
|
-
parseDOM() {
|
|
26663
|
-
return [
|
|
26664
|
-
{
|
|
26665
|
-
tag: "div.sd-document-section-block",
|
|
26666
|
-
priority: 60
|
|
26667
|
-
}
|
|
26668
|
-
];
|
|
26669
|
-
},
|
|
26670
|
-
renderDOM({ htmlAttributes }) {
|
|
26671
|
-
return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
26672
|
-
},
|
|
26673
27047
|
addAttributes() {
|
|
26674
27048
|
return {
|
|
26675
|
-
id: {},
|
|
26676
27049
|
sdBlockId: {
|
|
26677
27050
|
default: null,
|
|
26678
27051
|
keepOnSplit: false,
|
|
@@ -26681,212 +27054,131 @@ const DocumentSection = Node$1.create({
|
|
|
26681
27054
|
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
26682
27055
|
}
|
|
26683
27056
|
},
|
|
26684
|
-
|
|
26685
|
-
|
|
26686
|
-
|
|
26687
|
-
isLocked: { default: false }
|
|
27057
|
+
attributes: {
|
|
27058
|
+
rendered: false
|
|
27059
|
+
}
|
|
26688
27060
|
};
|
|
26689
27061
|
},
|
|
26690
|
-
|
|
26691
|
-
return
|
|
26692
|
-
|
|
27062
|
+
parseDOM() {
|
|
27063
|
+
return [
|
|
27064
|
+
{
|
|
27065
|
+
tag: `div[data-type="${this.name}"]`
|
|
27066
|
+
}
|
|
27067
|
+
];
|
|
27068
|
+
},
|
|
27069
|
+
renderDOM({ htmlAttributes }) {
|
|
27070
|
+
return [
|
|
27071
|
+
"div",
|
|
27072
|
+
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
27073
|
+
0
|
|
27074
|
+
];
|
|
27075
|
+
}
|
|
27076
|
+
});
|
|
27077
|
+
const ContentBlock = Node$1.create({
|
|
27078
|
+
name: "contentBlock",
|
|
27079
|
+
group: "inline",
|
|
27080
|
+
content: "",
|
|
27081
|
+
isolating: true,
|
|
27082
|
+
atom: true,
|
|
27083
|
+
inline: true,
|
|
27084
|
+
addOptions() {
|
|
27085
|
+
return {
|
|
27086
|
+
htmlAttributes: {
|
|
27087
|
+
contenteditable: false
|
|
27088
|
+
}
|
|
26693
27089
|
};
|
|
26694
27090
|
},
|
|
26695
|
-
|
|
27091
|
+
addAttributes() {
|
|
26696
27092
|
return {
|
|
26697
|
-
|
|
26698
|
-
|
|
26699
|
-
|
|
26700
|
-
|
|
26701
|
-
|
|
26702
|
-
* editor.commands.createDocumentSection({
|
|
26703
|
-
* id: 1,
|
|
26704
|
-
* title: 'Terms & Conditions',
|
|
26705
|
-
* isLocked: true,
|
|
26706
|
-
* html: '<p>Legal content...</p>'
|
|
26707
|
-
* })
|
|
26708
|
-
*/
|
|
26709
|
-
createDocumentSection: (options = {}) => ({ tr, state, dispatch, editor }) => {
|
|
26710
|
-
const { selection } = state;
|
|
26711
|
-
let { from: from2, to } = selection;
|
|
26712
|
-
let content = selection.content().content;
|
|
26713
|
-
const { html: optionsHTML, json: optionsJSON } = options;
|
|
26714
|
-
if (optionsHTML) {
|
|
26715
|
-
const html = htmlHandler(optionsHTML, this.editor);
|
|
26716
|
-
const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
|
|
26717
|
-
content = doc2.content;
|
|
26718
|
-
}
|
|
26719
|
-
if (optionsJSON) {
|
|
26720
|
-
content = this.editor.schema.nodeFromJSON(optionsJSON);
|
|
26721
|
-
}
|
|
26722
|
-
if (!content?.content?.length) {
|
|
26723
|
-
content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
|
|
26724
|
-
}
|
|
26725
|
-
if (!options.id) {
|
|
26726
|
-
const allSections = SectionHelpers.getAllSections(editor);
|
|
26727
|
-
options.id = allSections.length + 1;
|
|
26728
|
-
}
|
|
26729
|
-
if (!options.title) {
|
|
26730
|
-
options.title = "Document section";
|
|
26731
|
-
}
|
|
26732
|
-
const node = this.type.createAndFill(options, content);
|
|
26733
|
-
if (!node) return false;
|
|
26734
|
-
const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
|
|
26735
|
-
if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
|
|
26736
|
-
const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
|
|
26737
|
-
from2 = insertPos2;
|
|
26738
|
-
to = insertPos2;
|
|
26739
|
-
}
|
|
26740
|
-
tr.replaceRangeWith(from2, to, node);
|
|
26741
|
-
const nodeEnd = from2 + node.nodeSize;
|
|
26742
|
-
let shouldInsertParagraph = true;
|
|
26743
|
-
let insertPos = nodeEnd;
|
|
26744
|
-
if (nodeEnd >= tr.doc.content.size) {
|
|
26745
|
-
insertPos = tr.doc.content.size;
|
|
26746
|
-
if (insertPos > 0) {
|
|
26747
|
-
const $endPos = tr.doc.resolve(insertPos);
|
|
26748
|
-
if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
|
|
26749
|
-
shouldInsertParagraph = false;
|
|
26750
|
-
}
|
|
26751
|
-
}
|
|
26752
|
-
}
|
|
26753
|
-
if (shouldInsertParagraph) {
|
|
26754
|
-
const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
|
|
26755
|
-
tr.insert(insertPos, emptyParagraph);
|
|
26756
|
-
}
|
|
26757
|
-
if (dispatch) {
|
|
26758
|
-
tr.setMeta("documentSection", { action: "create" });
|
|
26759
|
-
dispatch(tr);
|
|
26760
|
-
setTimeout(() => {
|
|
26761
|
-
try {
|
|
26762
|
-
const currentState = editor.state;
|
|
26763
|
-
const docSize = currentState.doc.content.size;
|
|
26764
|
-
let targetPos = from2 + node.nodeSize;
|
|
26765
|
-
if (shouldInsertParagraph) {
|
|
26766
|
-
targetPos += 1;
|
|
26767
|
-
}
|
|
26768
|
-
targetPos = Math.min(targetPos, docSize);
|
|
26769
|
-
if (targetPos < docSize && targetPos > 0) {
|
|
26770
|
-
const newSelection = Selection.near(currentState.doc.resolve(targetPos));
|
|
26771
|
-
const newTr = currentState.tr.setSelection(newSelection);
|
|
26772
|
-
editor.view.dispatch(newTr);
|
|
26773
|
-
}
|
|
26774
|
-
} catch (e) {
|
|
26775
|
-
console.warn("Could not set delayed selection:", e);
|
|
26776
|
-
}
|
|
26777
|
-
}, 0);
|
|
27093
|
+
horizontalRule: {
|
|
27094
|
+
default: false,
|
|
27095
|
+
renderDOM: ({ horizontalRule }) => {
|
|
27096
|
+
if (!horizontalRule) return {};
|
|
27097
|
+
return { "data-horizontal-rule": "true" };
|
|
26778
27098
|
}
|
|
26779
|
-
return true;
|
|
26780
27099
|
},
|
|
26781
|
-
|
|
26782
|
-
|
|
26783
|
-
|
|
26784
|
-
|
|
26785
|
-
|
|
26786
|
-
|
|
26787
|
-
|
|
26788
|
-
|
|
26789
|
-
|
|
26790
|
-
|
|
26791
|
-
|
|
26792
|
-
const nodeStart = pos;
|
|
26793
|
-
const nodeEnd = nodeStart + node.nodeSize;
|
|
26794
|
-
const contentToPreserve = node.content;
|
|
26795
|
-
tr.delete(nodeStart, nodeEnd);
|
|
26796
|
-
if (contentToPreserve.size > 0) {
|
|
26797
|
-
tr.insert(nodeStart, contentToPreserve);
|
|
26798
|
-
}
|
|
26799
|
-
const newPos = Math.min(nodeStart, tr.doc.content.size);
|
|
26800
|
-
tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
|
|
26801
|
-
if (dispatch) {
|
|
26802
|
-
tr.setMeta("documentSection", { action: "delete" });
|
|
26803
|
-
dispatch(tr);
|
|
27100
|
+
size: {
|
|
27101
|
+
default: null,
|
|
27102
|
+
renderDOM: ({ size }) => {
|
|
27103
|
+
if (!size) return {};
|
|
27104
|
+
let style = "";
|
|
27105
|
+
if (size.top) style += `top: ${size.top}px; `;
|
|
27106
|
+
if (size.left) style += `left: ${size.left}px; `;
|
|
27107
|
+
if (size.width) style += `width: ${size.width.toString().endsWith("%") ? size.width : `${size.width}px`}; `;
|
|
27108
|
+
if (size.height)
|
|
27109
|
+
style += `height: ${size.height.toString().endsWith("%") ? size.height : `${size.height}px`}; `;
|
|
27110
|
+
return { style };
|
|
26804
27111
|
}
|
|
26805
|
-
return true;
|
|
26806
27112
|
},
|
|
26807
|
-
|
|
26808
|
-
|
|
26809
|
-
|
|
26810
|
-
|
|
26811
|
-
|
|
26812
|
-
|
|
26813
|
-
|
|
26814
|
-
removeSectionById: (id) => ({ tr, dispatch }) => {
|
|
26815
|
-
const sections = SectionHelpers.getAllSections(this.editor);
|
|
26816
|
-
const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
|
|
26817
|
-
if (!sectionToRemove) return false;
|
|
26818
|
-
const { pos, node } = sectionToRemove;
|
|
26819
|
-
const nodeStart = pos;
|
|
26820
|
-
const nodeEnd = nodeStart + node.nodeSize;
|
|
26821
|
-
tr.delete(nodeStart, nodeEnd);
|
|
26822
|
-
if (dispatch) {
|
|
26823
|
-
tr.setMeta("documentSection", { action: "delete", id });
|
|
26824
|
-
dispatch(tr);
|
|
27113
|
+
background: {
|
|
27114
|
+
default: null,
|
|
27115
|
+
renderDOM: (attrs) => {
|
|
27116
|
+
if (!attrs.background) return {};
|
|
27117
|
+
return {
|
|
27118
|
+
style: `background-color: ${attrs.background}`
|
|
27119
|
+
};
|
|
26825
27120
|
}
|
|
26826
|
-
return true;
|
|
26827
27121
|
},
|
|
27122
|
+
drawingContent: {
|
|
27123
|
+
rendered: false
|
|
27124
|
+
},
|
|
27125
|
+
attributes: {
|
|
27126
|
+
rendered: false
|
|
27127
|
+
}
|
|
27128
|
+
};
|
|
27129
|
+
},
|
|
27130
|
+
parseDOM() {
|
|
27131
|
+
return [
|
|
27132
|
+
{
|
|
27133
|
+
tag: `div[data-type="${this.name}"]`
|
|
27134
|
+
}
|
|
27135
|
+
];
|
|
27136
|
+
},
|
|
27137
|
+
renderDOM({ htmlAttributes }) {
|
|
27138
|
+
return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name })];
|
|
27139
|
+
},
|
|
27140
|
+
addCommands() {
|
|
27141
|
+
return {
|
|
26828
27142
|
/**
|
|
26829
|
-
*
|
|
27143
|
+
* Insert a horizontal rule
|
|
26830
27144
|
* @category Command
|
|
26831
|
-
* @param {number} id - Section to lock
|
|
26832
27145
|
* @example
|
|
26833
|
-
* editor.commands.
|
|
27146
|
+
* editor.commands.insertHorizontalRule()
|
|
27147
|
+
* @note Creates a visual separator between content sections
|
|
26834
27148
|
*/
|
|
26835
|
-
|
|
26836
|
-
|
|
26837
|
-
|
|
26838
|
-
|
|
26839
|
-
|
|
26840
|
-
|
|
26841
|
-
|
|
26842
|
-
|
|
26843
|
-
}
|
|
26844
|
-
return true;
|
|
27149
|
+
insertHorizontalRule: () => ({ commands: commands2 }) => {
|
|
27150
|
+
return commands2.insertContent({
|
|
27151
|
+
type: this.name,
|
|
27152
|
+
attrs: {
|
|
27153
|
+
horizontalRule: true,
|
|
27154
|
+
size: { width: "100%", height: 2 },
|
|
27155
|
+
background: "#e5e7eb"
|
|
27156
|
+
}
|
|
27157
|
+
});
|
|
26845
27158
|
},
|
|
26846
27159
|
/**
|
|
26847
|
-
*
|
|
27160
|
+
* Insert a content block
|
|
26848
27161
|
* @category Command
|
|
26849
|
-
* @param {
|
|
27162
|
+
* @param {ContentBlockConfig} config - Block configuration
|
|
26850
27163
|
* @example
|
|
26851
|
-
*
|
|
26852
|
-
* editor.commands.
|
|
26853
|
-
*
|
|
26854
|
-
*
|
|
26855
|
-
*
|
|
26856
|
-
*
|
|
27164
|
+
* // Insert a spacer block
|
|
27165
|
+
* editor.commands.insertContentBlock({ size: { height: 20 } })
|
|
27166
|
+
*
|
|
27167
|
+
* @example
|
|
27168
|
+
* // Insert a colored divider
|
|
27169
|
+
* editor.commands.insertContentBlock({
|
|
27170
|
+
* size: { width: '50%', height: 3 },
|
|
27171
|
+
* background: '#3b82f6'
|
|
26857
27172
|
* })
|
|
27173
|
+
* @note Used for spacing, dividers, and special inline content
|
|
26858
27174
|
*/
|
|
26859
|
-
|
|
26860
|
-
|
|
26861
|
-
|
|
26862
|
-
|
|
26863
|
-
|
|
26864
|
-
let newContent = null;
|
|
26865
|
-
if (html) {
|
|
26866
|
-
const htmlDoc = htmlHandler(html, editor || this.editor);
|
|
26867
|
-
const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
|
|
26868
|
-
newContent = doc2.content;
|
|
26869
|
-
}
|
|
26870
|
-
if (json) {
|
|
26871
|
-
newContent = (editor || this.editor).schema.nodeFromJSON(json);
|
|
26872
|
-
}
|
|
26873
|
-
if (!newContent) {
|
|
26874
|
-
newContent = node.content;
|
|
26875
|
-
}
|
|
26876
|
-
const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
|
|
26877
|
-
tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
|
|
26878
|
-
if (dispatch) {
|
|
26879
|
-
tr.setMeta("documentSection", { action: "update", id, attrs });
|
|
26880
|
-
dispatch(tr);
|
|
26881
|
-
}
|
|
26882
|
-
return true;
|
|
27175
|
+
insertContentBlock: (config) => ({ commands: commands2 }) => {
|
|
27176
|
+
return commands2.insertContent({
|
|
27177
|
+
type: this.name,
|
|
27178
|
+
attrs: config
|
|
27179
|
+
});
|
|
26883
27180
|
}
|
|
26884
27181
|
};
|
|
26885
|
-
},
|
|
26886
|
-
addHelpers() {
|
|
26887
|
-
return {
|
|
26888
|
-
...SectionHelpers
|
|
26889
|
-
};
|
|
26890
27182
|
}
|
|
26891
27183
|
});
|
|
26892
27184
|
const { findChildren } = helpers;
|
|
@@ -33454,7 +33746,8 @@ const nodeResizer = (nodeNames = ["image"], editor) => {
|
|
|
33454
33746
|
const prevSelection = prevState.selection;
|
|
33455
33747
|
if (selection.from !== prevSelection.from || selection.to !== prevSelection.to) {
|
|
33456
33748
|
setTimeout(() => {
|
|
33457
|
-
const
|
|
33749
|
+
const searchRoot = editorView?.dom;
|
|
33750
|
+
const selectedResizableWrapper = searchRoot?.querySelector(".sd-editor-resizable-wrapper");
|
|
33458
33751
|
if (selectedResizableWrapper) {
|
|
33459
33752
|
showResizeHandles(view2, selectedResizableWrapper);
|
|
33460
33753
|
} else {
|
|
@@ -33735,6 +34028,7 @@ const getStarterExtensions = () => {
|
|
|
33735
34028
|
Search,
|
|
33736
34029
|
StructuredContent,
|
|
33737
34030
|
StructuredContentBlock,
|
|
34031
|
+
StructuredContentCommands,
|
|
33738
34032
|
DocumentSection,
|
|
33739
34033
|
NodeResizer,
|
|
33740
34034
|
CustomSelection,
|
|
@@ -33768,6 +34062,7 @@ export {
|
|
|
33768
34062
|
SectionHelpers as o,
|
|
33769
34063
|
getAllowedImageDimensions as p,
|
|
33770
34064
|
replaceSelectionWithImagePlaceholder as r,
|
|
34065
|
+
shouldBypassContextMenu as s,
|
|
33771
34066
|
useHighContrastMode as u,
|
|
33772
34067
|
yUndoPluginKey as y
|
|
33773
34068
|
};
|