@harbour-enterprises/superdoc 0.21.0 → 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-D3zo7tPo.es.js → PdfViewer-CJdQmuIm.es.js} +1 -1
- package/dist/chunks/{PdfViewer-OZDJ7gwT.cjs → PdfViewer-DE1NR4Ve.cjs} +1 -1
- package/dist/chunks/{index-MzW5BVNd.es.js → index-B9sHxXr_.es.js} +55 -27
- package/dist/chunks/{index-CfYf4T_z.cjs → index-nfoifSpX.cjs} +55 -27
- package/dist/chunks/{super-editor.es-U-GVCd_F.cjs → super-editor.es-DAP-fnHo.cjs} +3469 -2438
- package/dist/chunks/{super-editor.es-Bntob7Wd.es.js → super-editor.es-_iVPQ8J8.es.js} +3469 -2438
- package/dist/core/SuperDoc.d.ts +5 -0
- package/dist/core/SuperDoc.d.ts.map +1 -1
- package/dist/core/types/index.d.ts +12 -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 +53 -44
- package/dist/super-editor/ai-writer.es.js +2 -2
- package/dist/super-editor/chunks/{converter-3xnF_NHq.js → converter-DK1NMJZB.js} +1148 -748
- package/dist/super-editor/chunks/{docx-zipper-CZdELYi-.js → docx-zipper-CmK8TyNb.js} +73 -12
- package/dist/super-editor/chunks/{editor-BqYH4kDD.js → editor-YR4uV-dp.js} +1917 -1606
- package/dist/super-editor/chunks/{toolbar-TkaE2kKM.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/components/slash-menu/menuItems.d.ts +5 -1
- package/dist/super-editor/src/components/slash-menu/tests/testHelpers.d.ts +466 -0
- package/dist/super-editor/src/components/slash-menu/utils.d.ts +9 -2
- package/dist/super-editor/src/core/DocxZipper.d.ts +1 -1
- package/dist/super-editor/src/core/commands/__tests__/schemaWithLists.d.ts +2 -0
- package/dist/super-editor/src/core/commands/__tests__/testHelpers.d.ts +4 -0
- package/dist/super-editor/src/core/commands/__tests__/testSchema.d.ts +2 -0
- package/dist/super-editor/src/core/commands/tests/commandTestUtils.d.ts +7 -0
- package/dist/super-editor/src/core/commands/tests/test-schema.d.ts +2 -0
- 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/core/super-converter/v3/handlers/mc/altermateContent/alternate-content-translator.d.ts +6 -0
- package/dist/super-editor/src/core/super-converter/v3/handlers/mc/altermateContent/index.d.ts +1 -0
- package/dist/super-editor/src/extensions/custom-selection/custom-selection.d.ts +5 -0
- 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/tests/helpers/helpers.d.ts +1 -0
- package/dist/super-editor/src/utils/contextmenu-helpers.d.ts +24 -0
- package/dist/super-editor/style.css +9 -0
- package/dist/super-editor/super-editor.es.js +454 -154
- 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 +3528 -2469
- package/dist/superdoc.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/super-editor/src/extensions/run-item/index.d.ts +0 -1
- package/dist/super-editor/src/extensions/run-item/run-item.d.ts +0 -26
|
@@ -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") {
|
|
@@ -14562,6 +14553,8 @@ const _Editor = class _Editor extends EventEmitter {
|
|
|
14562
14553
|
element.style.isolation = "isolate";
|
|
14563
14554
|
proseMirror.style.outline = "none";
|
|
14564
14555
|
proseMirror.style.border = "none";
|
|
14556
|
+
element.style.backgroundColor = "#fff";
|
|
14557
|
+
proseMirror.style.backgroundColor = "#fff";
|
|
14565
14558
|
const { typeface, fontSizePt, fontFamilyCss } = this.converter.getDocumentDefaultStyles() ?? {};
|
|
14566
14559
|
const resolvedFontFamily = fontFamilyCss || typeface;
|
|
14567
14560
|
if (resolvedFontFamily) {
|
|
@@ -14818,7 +14811,8 @@ const _Editor = class _Editor extends EventEmitter {
|
|
|
14818
14811
|
files: this.options.content
|
|
14819
14812
|
},
|
|
14820
14813
|
media,
|
|
14821
|
-
true
|
|
14814
|
+
true,
|
|
14815
|
+
updatedDocs
|
|
14822
14816
|
);
|
|
14823
14817
|
return updatedDocs;
|
|
14824
14818
|
}
|
|
@@ -14884,7 +14878,7 @@ const _Editor = class _Editor extends EventEmitter {
|
|
|
14884
14878
|
* @returns {Object | void} Migration results
|
|
14885
14879
|
*/
|
|
14886
14880
|
processCollaborationMigrations() {
|
|
14887
|
-
console.debug("[checkVersionMigrations] Current editor version", "0.
|
|
14881
|
+
console.debug("[checkVersionMigrations] Current editor version", "0.21.0");
|
|
14888
14882
|
if (!this.options.ydoc) return;
|
|
14889
14883
|
const metaMap = this.options.ydoc.getMap("meta");
|
|
14890
14884
|
let docVersion = metaMap.get("version");
|
|
@@ -15378,9 +15372,11 @@ createView_fn = function(element) {
|
|
|
15378
15372
|
isEditMode: false,
|
|
15379
15373
|
documentMode: this.options.documentMode
|
|
15380
15374
|
});
|
|
15381
|
-
const pm =
|
|
15382
|
-
pm
|
|
15383
|
-
|
|
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
|
+
}
|
|
15384
15380
|
}
|
|
15385
15381
|
setWordSelection(view, pos);
|
|
15386
15382
|
}
|
|
@@ -16971,583 +16967,1605 @@ const SlashMenu = Extension.create({
|
|
|
16971
16967
|
return this.editor.options.isHeadless ? [] : [slashMenuPlugin];
|
|
16972
16968
|
}
|
|
16973
16969
|
});
|
|
16974
|
-
|
|
16975
|
-
|
|
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
|
-
|
|
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
|
+
);
|
|
17023
17061
|
}
|
|
17024
|
-
}
|
|
17062
|
+
}
|
|
17063
|
+
if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
|
|
17064
|
+
return false;
|
|
17065
|
+
}
|
|
17066
|
+
return true;
|
|
17025
17067
|
}
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
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;
|
|
17033
17075
|
}
|
|
17034
|
-
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
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);
|
|
17041
17133
|
view.dispatch(transaction);
|
|
17042
|
-
});
|
|
17043
|
-
if (handled) {
|
|
17044
|
-
tr.setMeta("preventDispatch", true);
|
|
17045
17134
|
}
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
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",
|
|
17052
17181
|
inline: true,
|
|
17053
17182
|
content: "inline*",
|
|
17054
|
-
|
|
17055
|
-
|
|
17183
|
+
isolating: true,
|
|
17184
|
+
atom: false,
|
|
17185
|
+
// false - has editable content.
|
|
17186
|
+
draggable: true,
|
|
17056
17187
|
addOptions() {
|
|
17057
17188
|
return {
|
|
17058
17189
|
htmlAttributes: {
|
|
17059
|
-
|
|
17190
|
+
class: structuredContentClass$1,
|
|
17191
|
+
"aria-label": "Structured content node"
|
|
17060
17192
|
}
|
|
17061
17193
|
};
|
|
17062
17194
|
},
|
|
17063
17195
|
addAttributes() {
|
|
17064
17196
|
return {
|
|
17065
|
-
|
|
17197
|
+
id: {
|
|
17066
17198
|
default: null,
|
|
17067
|
-
|
|
17068
|
-
|
|
17199
|
+
parseDOM: (elem) => elem.getAttribute("data-id"),
|
|
17200
|
+
renderDOM: (attrs) => {
|
|
17201
|
+
if (!attrs.id) return {};
|
|
17202
|
+
return { "data-id": attrs.id };
|
|
17203
|
+
}
|
|
17069
17204
|
},
|
|
17070
|
-
|
|
17205
|
+
tag: {
|
|
17071
17206
|
default: null,
|
|
17072
|
-
|
|
17073
|
-
|
|
17207
|
+
parseDOM: (elem) => elem.getAttribute("data-tag"),
|
|
17208
|
+
renderDOM: (attrs) => {
|
|
17209
|
+
if (!attrs.tag) return {};
|
|
17210
|
+
return { "data-tag": attrs.tag };
|
|
17211
|
+
}
|
|
17074
17212
|
},
|
|
17075
|
-
|
|
17213
|
+
alias: {
|
|
17076
17214
|
default: null,
|
|
17077
|
-
|
|
17078
|
-
|
|
17215
|
+
parseDOM: (elem) => elem.getAttribute("data-alias"),
|
|
17216
|
+
renderDOM: (attrs) => {
|
|
17217
|
+
if (!attrs.alias) return {};
|
|
17218
|
+
return { "data-alias": attrs.alias };
|
|
17219
|
+
}
|
|
17079
17220
|
},
|
|
17080
|
-
|
|
17081
|
-
|
|
17082
|
-
rendered: false,
|
|
17083
|
-
keepOnSplit: true
|
|
17221
|
+
sdtPr: {
|
|
17222
|
+
rendered: false
|
|
17084
17223
|
}
|
|
17085
17224
|
};
|
|
17086
17225
|
},
|
|
17087
|
-
addCommands() {
|
|
17088
|
-
return {
|
|
17089
|
-
splitRun
|
|
17090
|
-
};
|
|
17091
|
-
},
|
|
17092
17226
|
parseDOM() {
|
|
17093
|
-
return [{ tag: "span[data-
|
|
17227
|
+
return [{ tag: "span[data-structured-content]" }];
|
|
17094
17228
|
},
|
|
17095
17229
|
renderDOM({ htmlAttributes }) {
|
|
17096
|
-
|
|
17097
|
-
|
|
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
|
+
};
|
|
17098
17242
|
}
|
|
17099
17243
|
});
|
|
17100
|
-
|
|
17101
|
-
|
|
17102
|
-
|
|
17103
|
-
|
|
17104
|
-
|
|
17105
|
-
|
|
17106
|
-
|
|
17107
|
-
|
|
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,
|
|
17108
17294
|
addOptions() {
|
|
17109
17295
|
return {
|
|
17110
|
-
itemTypeName: "listItem",
|
|
17111
17296
|
htmlAttributes: {
|
|
17112
|
-
|
|
17113
|
-
|
|
17114
|
-
|
|
17115
|
-
keepAttributes: false
|
|
17297
|
+
class: structuredContentClass,
|
|
17298
|
+
"aria-label": "Structured content block node"
|
|
17299
|
+
}
|
|
17116
17300
|
};
|
|
17117
17301
|
},
|
|
17118
|
-
parseDOM() {
|
|
17119
|
-
return [{ tag: "ul" }];
|
|
17120
|
-
},
|
|
17121
|
-
renderDOM({ htmlAttributes }) {
|
|
17122
|
-
const attributes = Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes);
|
|
17123
|
-
return ["ul", attributes, 0];
|
|
17124
|
-
},
|
|
17125
17302
|
addAttributes() {
|
|
17126
17303
|
return {
|
|
17127
|
-
|
|
17128
|
-
default:
|
|
17129
|
-
|
|
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
|
+
}
|
|
17130
17311
|
},
|
|
17131
|
-
|
|
17132
|
-
|
|
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
|
+
}
|
|
17133
17319
|
},
|
|
17134
|
-
|
|
17320
|
+
alias: {
|
|
17135
17321
|
default: null,
|
|
17136
|
-
|
|
17137
|
-
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
17322
|
+
parseDOM: (elem) => elem.getAttribute("data-alias"),
|
|
17138
17323
|
renderDOM: (attrs) => {
|
|
17139
|
-
|
|
17324
|
+
if (!attrs.alias) return {};
|
|
17325
|
+
return { "data-alias": attrs.alias };
|
|
17140
17326
|
}
|
|
17141
17327
|
},
|
|
17142
|
-
|
|
17143
|
-
rendered: false
|
|
17144
|
-
keepOnSplit: true
|
|
17328
|
+
sdtPr: {
|
|
17329
|
+
rendered: false
|
|
17145
17330
|
}
|
|
17146
17331
|
};
|
|
17147
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",
|
|
17148
17386
|
addCommands() {
|
|
17149
17387
|
return {
|
|
17150
17388
|
/**
|
|
17151
|
-
*
|
|
17389
|
+
* Inserts a structured content inline at selection.
|
|
17152
17390
|
* @category Command
|
|
17153
|
-
* @
|
|
17154
|
-
* // Toggle bullet list on selected text
|
|
17155
|
-
* editor.commands.toggleBulletList()
|
|
17156
|
-
* @note Converts selected paragraphs to list items or removes list formatting
|
|
17391
|
+
* @param {StructuredContentInlineInsert} options
|
|
17157
17392
|
*/
|
|
17158
|
-
|
|
17159
|
-
|
|
17160
|
-
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17164
|
-
|
|
17165
|
-
|
|
17166
|
-
return this.editor.commands.toggleBulletList();
|
|
17167
|
-
}
|
|
17168
|
-
};
|
|
17169
|
-
},
|
|
17170
|
-
addInputRules() {
|
|
17171
|
-
return [
|
|
17172
|
-
new InputRule({
|
|
17173
|
-
match: inputRegex$1,
|
|
17174
|
-
handler: ({ state, range }) => {
|
|
17175
|
-
const $pos = state.selection.$from;
|
|
17176
|
-
const listItemType = state.schema.nodes.listItem;
|
|
17177
|
-
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
17178
|
-
if ($pos.node(depth).type === listItemType) {
|
|
17179
|
-
return null;
|
|
17180
|
-
}
|
|
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);
|
|
17181
17401
|
}
|
|
17182
|
-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
|
|
17186
|
-
|
|
17187
|
-
|
|
17188
|
-
|
|
17189
|
-
|
|
17190
|
-
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
name: "orderedList",
|
|
17197
|
-
group: "block list",
|
|
17198
|
-
selectable: false,
|
|
17199
|
-
content() {
|
|
17200
|
-
return `${this.options.itemTypeName}+`;
|
|
17201
|
-
},
|
|
17202
|
-
addOptions() {
|
|
17203
|
-
return {
|
|
17204
|
-
itemTypeName: "listItem",
|
|
17205
|
-
htmlAttributes: {
|
|
17206
|
-
"aria-label": "Ordered list node"
|
|
17207
|
-
},
|
|
17208
|
-
keepMarks: true,
|
|
17209
|
-
keepAttributes: false,
|
|
17210
|
-
listStyleTypes: ["decimal", "lowerAlpha", "lowerRoman"]
|
|
17211
|
-
};
|
|
17212
|
-
},
|
|
17213
|
-
addAttributes() {
|
|
17214
|
-
return {
|
|
17215
|
-
order: {
|
|
17216
|
-
default: 1,
|
|
17217
|
-
parseDOM: (element) => {
|
|
17218
|
-
return element.hasAttribute("start") ? parseInt(element.getAttribute("start") || "", 10) : 1;
|
|
17219
|
-
},
|
|
17220
|
-
renderDOM: (attrs) => {
|
|
17221
|
-
return {
|
|
17222
|
-
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"
|
|
17223
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);
|
|
17224
17424
|
}
|
|
17425
|
+
return true;
|
|
17225
17426
|
},
|
|
17226
|
-
|
|
17227
|
-
|
|
17228
|
-
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
}
|
|
17233
|
-
|
|
17234
|
-
|
|
17235
|
-
|
|
17236
|
-
|
|
17237
|
-
|
|
17238
|
-
|
|
17239
|
-
|
|
17240
|
-
|
|
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"
|
|
17241
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);
|
|
17242
17465
|
}
|
|
17243
|
-
|
|
17466
|
+
return true;
|
|
17244
17467
|
},
|
|
17245
|
-
|
|
17246
|
-
|
|
17247
|
-
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
|
|
17251
|
-
|
|
17252
|
-
|
|
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;
|
|
17253
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;
|
|
17254
17511
|
},
|
|
17255
|
-
"list-style-type": {
|
|
17256
|
-
default: "decimal",
|
|
17257
|
-
rendered: false
|
|
17258
|
-
},
|
|
17259
|
-
attributes: {
|
|
17260
|
-
rendered: false,
|
|
17261
|
-
keepOnSplit: true
|
|
17262
|
-
}
|
|
17263
|
-
};
|
|
17264
|
-
},
|
|
17265
|
-
parseDOM() {
|
|
17266
|
-
return [{ tag: "ol" }];
|
|
17267
|
-
},
|
|
17268
|
-
renderDOM({ htmlAttributes }) {
|
|
17269
|
-
const { start: start2, ...restAttributes } = htmlAttributes;
|
|
17270
|
-
return start2 === 1 ? ["ol", Attribute.mergeAttributes(this.options.htmlAttributes, restAttributes), 0] : ["ol", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
17271
|
-
},
|
|
17272
|
-
addCommands() {
|
|
17273
|
-
return {
|
|
17274
17512
|
/**
|
|
17275
|
-
*
|
|
17513
|
+
* Removes a structured content.
|
|
17276
17514
|
* @category Command
|
|
17277
|
-
* @
|
|
17278
|
-
* editor.commands.toggleOrderedList()
|
|
17279
|
-
* @note Converts selection to ordered list or back to paragraphs
|
|
17515
|
+
* @param {Array<{ node: Node, pos: number }>} structuredContentTags
|
|
17280
17516
|
*/
|
|
17281
|
-
|
|
17282
|
-
|
|
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;
|
|
17283
17533
|
},
|
|
17284
17534
|
/**
|
|
17285
|
-
*
|
|
17535
|
+
* Removes a structured content by ID.
|
|
17286
17536
|
* @category Command
|
|
17287
|
-
* @param {
|
|
17288
|
-
* @param {number} pos - Starting position
|
|
17289
|
-
* @example
|
|
17290
|
-
* editor.commands.restartListNodes(nodes, position)
|
|
17291
|
-
* @note Resets list numbering for specified nodes
|
|
17537
|
+
* @param {string | string[]} idOrIds
|
|
17292
17538
|
*/
|
|
17293
|
-
|
|
17294
|
-
|
|
17295
|
-
|
|
17296
|
-
|
|
17297
|
-
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
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
|
+
}
|
|
17308
17555
|
return true;
|
|
17309
17556
|
},
|
|
17310
17557
|
/**
|
|
17311
|
-
*
|
|
17558
|
+
* Removes a structured content at cursor, preserving its content.
|
|
17312
17559
|
* @category Command
|
|
17313
|
-
* @example
|
|
17314
|
-
* editor.commands.updateOrderedListStyleType()
|
|
17315
|
-
* @note Cycles through decimal -> lowerAlpha -> lowerRoman based on depth
|
|
17316
17560
|
*/
|
|
17317
|
-
|
|
17318
|
-
|
|
17319
|
-
|
|
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) {
|
|
17320
17565
|
return true;
|
|
17321
17566
|
}
|
|
17322
17567
|
if (dispatch) {
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
if (currentListStyle !== listStyle && nodeAtPos.eq(list.node)) {
|
|
17329
|
-
tr.setNodeMarkup(list.pos, void 0, {
|
|
17330
|
-
...list.node.attrs,
|
|
17331
|
-
...{
|
|
17332
|
-
"list-style-type": listStyle
|
|
17333
|
-
}
|
|
17334
|
-
});
|
|
17335
|
-
}
|
|
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);
|
|
17336
17573
|
}
|
|
17337
17574
|
return true;
|
|
17338
17575
|
}
|
|
17339
17576
|
};
|
|
17340
17577
|
},
|
|
17341
|
-
|
|
17578
|
+
addHelpers() {
|
|
17342
17579
|
return {
|
|
17343
|
-
|
|
17344
|
-
return this.editor.commands.toggleOrderedList();
|
|
17345
|
-
}
|
|
17580
|
+
...structuredContentHelpers
|
|
17346
17581
|
};
|
|
17347
|
-
},
|
|
17348
|
-
addInputRules() {
|
|
17349
|
-
return [
|
|
17350
|
-
new InputRule({
|
|
17351
|
-
match: inputRegex,
|
|
17352
|
-
handler: ({ state, range }) => {
|
|
17353
|
-
const $pos = state.selection.$from;
|
|
17354
|
-
const listItemType = state.schema.nodes.listItem;
|
|
17355
|
-
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
17356
|
-
if ($pos.node(depth).type === listItemType) {
|
|
17357
|
-
return null;
|
|
17358
|
-
}
|
|
17359
|
-
}
|
|
17360
|
-
const { tr } = state;
|
|
17361
|
-
tr.delete(range.from, range.to);
|
|
17362
|
-
ListHelpers.createNewList({
|
|
17363
|
-
listType: this.type,
|
|
17364
|
-
tr,
|
|
17365
|
-
editor: this.editor
|
|
17366
|
-
});
|
|
17367
|
-
}
|
|
17368
|
-
})
|
|
17369
|
-
];
|
|
17370
17582
|
}
|
|
17371
17583
|
});
|
|
17372
|
-
const
|
|
17373
|
-
|
|
17374
|
-
return handler ? handler(listLevel, lvlText, customFormat) : null;
|
|
17375
|
-
};
|
|
17376
|
-
const handleDecimal = (path, lvlText) => generateNumbering(path, lvlText, String);
|
|
17377
|
-
const handleRoman = (path, lvlText) => generateNumbering(path, lvlText, intToRoman);
|
|
17378
|
-
const handleLowerRoman = (path, lvlText) => handleRoman(path, lvlText).toLowerCase();
|
|
17379
|
-
const handleLowerAlpha = (path, lvlText) => handleAlpha(path, lvlText).toLowerCase();
|
|
17380
|
-
const handleAlpha = (path, lvlText) => generateNumbering(path, lvlText, (p) => intToAlpha(p));
|
|
17381
|
-
const handleOrdinal = (path, lvlText) => generateNumbering(path, lvlText, ordinalFormatter);
|
|
17382
|
-
const handleCustom = (path, lvlText, customFormat) => generateFromCustom(path, lvlText, customFormat);
|
|
17383
|
-
const handleJapaneseCounting = (path, lvlText) => generateNumbering(path, lvlText, intToJapaneseCounting);
|
|
17384
|
-
const listIndexMap = {
|
|
17385
|
-
decimal: handleDecimal,
|
|
17386
|
-
lowerRoman: handleLowerRoman,
|
|
17387
|
-
upperRoman: handleRoman,
|
|
17388
|
-
lowerLetter: handleLowerAlpha,
|
|
17389
|
-
upperLetter: handleAlpha,
|
|
17390
|
-
ordinal: handleOrdinal,
|
|
17391
|
-
custom: handleCustom,
|
|
17392
|
-
japaneseCounting: handleJapaneseCounting
|
|
17393
|
-
};
|
|
17394
|
-
const createNumbering = (values, lvlText) => {
|
|
17395
|
-
return values.reduce((acc, value, index2) => {
|
|
17396
|
-
return value > 9 ? acc.replace(/^0/, "").replace(`%${index2 + 1}`, value) : acc.replace(`%${index2 + 1}`, value);
|
|
17397
|
-
}, lvlText);
|
|
17584
|
+
const randomId = () => {
|
|
17585
|
+
return Math.floor(Math.random() * 4294967295).toString();
|
|
17398
17586
|
};
|
|
17399
|
-
|
|
17400
|
-
|
|
17401
|
-
|
|
17402
|
-
|
|
17403
|
-
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
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);
|
|
17596
|
+
}
|
|
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);
|
|
17409
17613
|
};
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
const
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
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);
|
|
17418
17623
|
};
|
|
17419
|
-
const
|
|
17420
|
-
|
|
17421
|
-
|
|
17422
|
-
|
|
17423
|
-
|
|
17424
|
-
|
|
17425
|
-
|
|
17426
|
-
|
|
17427
|
-
|
|
17428
|
-
{ value: 40, numeral: "XL" },
|
|
17429
|
-
{ value: 10, numeral: "X" },
|
|
17430
|
-
{ value: 9, numeral: "IX" },
|
|
17431
|
-
{ value: 5, numeral: "V" },
|
|
17432
|
-
{ value: 4, numeral: "IV" },
|
|
17433
|
-
{ value: 1, numeral: "I" }
|
|
17434
|
-
];
|
|
17435
|
-
let result = "";
|
|
17436
|
-
for (const { value, numeral } of romanNumeralMap) {
|
|
17437
|
-
while (num >= value) {
|
|
17438
|
-
result += numeral;
|
|
17439
|
-
num -= value;
|
|
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 });
|
|
17440
17633
|
}
|
|
17441
|
-
}
|
|
17442
|
-
return
|
|
17634
|
+
});
|
|
17635
|
+
return sections;
|
|
17443
17636
|
};
|
|
17444
|
-
const
|
|
17445
|
-
|
|
17446
|
-
const
|
|
17447
|
-
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
|
|
17451
|
-
|
|
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
|
+
});
|
|
17452
17654
|
return result;
|
|
17453
17655
|
};
|
|
17454
|
-
const
|
|
17455
|
-
const
|
|
17456
|
-
const
|
|
17457
|
-
|
|
17458
|
-
|
|
17459
|
-
let
|
|
17460
|
-
|
|
17461
|
-
let unitIndex = 0;
|
|
17462
|
-
while (tempNum > 0) {
|
|
17463
|
-
const digit = tempNum % 10;
|
|
17464
|
-
if (digit !== 0) {
|
|
17465
|
-
const digitStr = digit === 1 && unitIndex > 0 ? "" : digits[digit];
|
|
17466
|
-
result = digitStr + (unitIndex > 0 ? units[unitIndex] : "") + result;
|
|
17467
|
-
} else if (result && tempNum > 0) {
|
|
17468
|
-
if (!result.startsWith("零") && tempNum % 100 !== 0) {
|
|
17469
|
-
result = "零" + result;
|
|
17470
|
-
}
|
|
17471
|
-
}
|
|
17472
|
-
tempNum = Math.floor(tempNum / 10);
|
|
17473
|
-
unitIndex++;
|
|
17474
|
-
if (unitIndex > 3) break;
|
|
17475
|
-
}
|
|
17476
|
-
if (num >= 10 && num < 20) {
|
|
17477
|
-
result = result.replace(/^一十/, "十");
|
|
17478
|
-
}
|
|
17479
|
-
return result;
|
|
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;
|
|
17480
17663
|
};
|
|
17481
|
-
const
|
|
17482
|
-
const
|
|
17483
|
-
const
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
|
|
17491
|
-
|
|
17492
|
-
|
|
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()
|
|
17493
17678
|
});
|
|
17494
|
-
}
|
|
17679
|
+
});
|
|
17680
|
+
return result;
|
|
17495
17681
|
};
|
|
17496
|
-
|
|
17497
|
-
|
|
17498
|
-
|
|
17499
|
-
|
|
17500
|
-
|
|
17501
|
-
|
|
17502
|
-
|
|
17503
|
-
|
|
17504
|
-
|
|
17505
|
-
const
|
|
17506
|
-
|
|
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;
|
|
17507
17717
|
};
|
|
17508
|
-
const
|
|
17509
|
-
|
|
17718
|
+
const SectionHelpers = {
|
|
17719
|
+
getAllSections,
|
|
17720
|
+
exportSectionsToHTML,
|
|
17721
|
+
exportSectionsToJSON,
|
|
17722
|
+
getLinkedSectionEditor
|
|
17510
17723
|
};
|
|
17511
|
-
const
|
|
17512
|
-
name: "
|
|
17513
|
-
|
|
17514
|
-
|
|
17515
|
-
|
|
17516
|
-
|
|
17517
|
-
|
|
17518
|
-
|
|
17519
|
-
|
|
17520
|
-
|
|
17521
|
-
|
|
17522
|
-
|
|
17523
|
-
|
|
17524
|
-
|
|
17525
|
-
|
|
17526
|
-
|
|
17527
|
-
|
|
17528
|
-
|
|
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 } : {};
|
|
17529
17758
|
}
|
|
17530
17759
|
},
|
|
17531
|
-
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
|
|
17538
|
-
|
|
17539
|
-
|
|
17540
|
-
|
|
17541
|
-
|
|
17542
|
-
|
|
17543
|
-
|
|
17544
|
-
|
|
17545
|
-
|
|
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
|
+
},
|
|
18554
|
+
props: {
|
|
18555
|
+
handleDOMEvents: {
|
|
18556
|
+
contextmenu: (view, event) => {
|
|
18557
|
+
if (shouldAllowNativeContextMenu(event)) {
|
|
18558
|
+
return false;
|
|
18559
|
+
}
|
|
18560
|
+
event.preventDefault();
|
|
18561
|
+
const { selection } = view.state;
|
|
18562
|
+
if (!selection.empty) {
|
|
17546
18563
|
view.dispatch(
|
|
17547
18564
|
setFocusMeta(view.state.tr, {
|
|
17548
18565
|
focused: true,
|
|
17549
18566
|
preservedSelection: selection,
|
|
17550
|
-
showVisualSelection: true
|
|
18567
|
+
showVisualSelection: true,
|
|
18568
|
+
skipFocusReset: true
|
|
17551
18569
|
})
|
|
17552
18570
|
);
|
|
17553
18571
|
}
|
|
@@ -17558,6 +18576,9 @@ const CustomSelection = Extension.create({
|
|
|
17558
18576
|
},
|
|
17559
18577
|
mousedown: (view, event) => {
|
|
17560
18578
|
if (event.button === 2) {
|
|
18579
|
+
if (shouldAllowNativeContextMenu(event)) {
|
|
18580
|
+
return false;
|
|
18581
|
+
}
|
|
17561
18582
|
event.preventDefault();
|
|
17562
18583
|
const { selection: selection2 } = view.state;
|
|
17563
18584
|
if (!selection2.empty) {
|
|
@@ -17565,7 +18586,8 @@ const CustomSelection = Extension.create({
|
|
|
17565
18586
|
setFocusMeta(view.state.tr, {
|
|
17566
18587
|
focused: true,
|
|
17567
18588
|
preservedSelection: selection2,
|
|
17568
|
-
showVisualSelection: true
|
|
18589
|
+
showVisualSelection: true,
|
|
18590
|
+
skipFocusReset: true
|
|
17569
18591
|
})
|
|
17570
18592
|
);
|
|
17571
18593
|
this.editor.setOptions({
|
|
@@ -17588,7 +18610,8 @@ const CustomSelection = Extension.create({
|
|
|
17588
18610
|
setFocusMeta(view.state.tr, {
|
|
17589
18611
|
focused: true,
|
|
17590
18612
|
preservedSelection: selection,
|
|
17591
|
-
showVisualSelection: true
|
|
18613
|
+
showVisualSelection: true,
|
|
18614
|
+
skipFocusReset: false
|
|
17592
18615
|
})
|
|
17593
18616
|
);
|
|
17594
18617
|
this.editor.setOptions({
|
|
@@ -17606,7 +18629,8 @@ const CustomSelection = Extension.create({
|
|
|
17606
18629
|
setFocusMeta(view.state.tr, {
|
|
17607
18630
|
focused: true,
|
|
17608
18631
|
preservedSelection: selection,
|
|
17609
|
-
showVisualSelection: true
|
|
18632
|
+
showVisualSelection: true,
|
|
18633
|
+
skipFocusReset: false
|
|
17610
18634
|
})
|
|
17611
18635
|
);
|
|
17612
18636
|
}
|
|
@@ -17617,7 +18641,8 @@ const CustomSelection = Extension.create({
|
|
|
17617
18641
|
setFocusMeta(view.state.tr, {
|
|
17618
18642
|
focused: false,
|
|
17619
18643
|
preservedSelection: null,
|
|
17620
|
-
showVisualSelection: false
|
|
18644
|
+
showVisualSelection: false,
|
|
18645
|
+
skipFocusReset: false
|
|
17621
18646
|
})
|
|
17622
18647
|
);
|
|
17623
18648
|
if (!selection.empty && !this.editor.options.element?.contains(target)) {
|
|
@@ -17634,12 +18659,20 @@ const CustomSelection = Extension.create({
|
|
|
17634
18659
|
const isElement2 = target instanceof Element;
|
|
17635
18660
|
const isToolbarBtn = isElement2 && isToolbarButton(target);
|
|
17636
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
|
+
}
|
|
17637
18669
|
if (!isToolbarBtn && !isToolbarInp) {
|
|
17638
18670
|
view.dispatch(
|
|
17639
18671
|
setFocusMeta(view.state.tr, {
|
|
17640
18672
|
focused: false,
|
|
17641
18673
|
preservedSelection: null,
|
|
17642
|
-
showVisualSelection: false
|
|
18674
|
+
showVisualSelection: false,
|
|
18675
|
+
skipFocusReset: false
|
|
17643
18676
|
})
|
|
17644
18677
|
);
|
|
17645
18678
|
}
|
|
@@ -17650,12 +18683,16 @@ const CustomSelection = Extension.create({
|
|
|
17650
18683
|
const isToolbarBtn = isElement2 && isToolbarButton(target);
|
|
17651
18684
|
const isToolbarInp = isElement2 && isToolbarInput(target);
|
|
17652
18685
|
const state = getFocusState(view.state);
|
|
18686
|
+
if (state?.skipFocusReset) {
|
|
18687
|
+
return false;
|
|
18688
|
+
}
|
|
17653
18689
|
if (isToolbarBtn || isToolbarInp) {
|
|
17654
18690
|
view.dispatch(
|
|
17655
18691
|
setFocusMeta(view.state.tr, {
|
|
17656
18692
|
focused: true,
|
|
17657
18693
|
preservedSelection: state.preservedSelection || view.state.selection,
|
|
17658
|
-
showVisualSelection: true
|
|
18694
|
+
showVisualSelection: true,
|
|
18695
|
+
skipFocusReset: false
|
|
17659
18696
|
})
|
|
17660
18697
|
);
|
|
17661
18698
|
} else {
|
|
@@ -17663,7 +18700,8 @@ const CustomSelection = Extension.create({
|
|
|
17663
18700
|
setFocusMeta(view.state.tr, {
|
|
17664
18701
|
focused: false,
|
|
17665
18702
|
preservedSelection: null,
|
|
17666
|
-
showVisualSelection: false
|
|
18703
|
+
showVisualSelection: false,
|
|
18704
|
+
skipFocusReset: false
|
|
17667
18705
|
})
|
|
17668
18706
|
);
|
|
17669
18707
|
}
|
|
@@ -18509,7 +19547,7 @@ class ListItemNodeView {
|
|
|
18509
19547
|
this.decorations = decorations;
|
|
18510
19548
|
this.view = editor.view;
|
|
18511
19549
|
this.getPos = getPos;
|
|
18512
|
-
__privateMethod(this, _ListItemNodeView_instances,
|
|
19550
|
+
__privateMethod(this, _ListItemNodeView_instances, init_fn3).call(this);
|
|
18513
19551
|
activeListItemNodeViews.add(this);
|
|
18514
19552
|
}
|
|
18515
19553
|
refreshIndentStyling() {
|
|
@@ -18570,7 +19608,7 @@ class ListItemNodeView {
|
|
|
18570
19608
|
}
|
|
18571
19609
|
}
|
|
18572
19610
|
_ListItemNodeView_instances = new WeakSet();
|
|
18573
|
-
|
|
19611
|
+
init_fn3 = function() {
|
|
18574
19612
|
const { attrs } = this.node;
|
|
18575
19613
|
const { listLevel, listNumberingType, lvlText, numId, level, customFormat } = attrs;
|
|
18576
19614
|
let orderMarker = "";
|
|
@@ -25679,984 +26717,335 @@ const PageNumber = Node$1.create({
|
|
|
25679
26717
|
}
|
|
25680
26718
|
};
|
|
25681
26719
|
},
|
|
25682
|
-
addAttributes() {
|
|
25683
|
-
return {
|
|
25684
|
-
marksAsAttrs: {
|
|
25685
|
-
default: null,
|
|
25686
|
-
rendered: false
|
|
25687
|
-
}
|
|
25688
|
-
};
|
|
25689
|
-
},
|
|
25690
|
-
addNodeView() {
|
|
25691
|
-
return ({ node, editor, getPos, decorations }) => {
|
|
25692
|
-
const htmlAttributes = this.options.htmlAttributes;
|
|
25693
|
-
return new AutoPageNumberNodeView(node, getPos, decorations, editor, htmlAttributes);
|
|
25694
|
-
};
|
|
25695
|
-
},
|
|
25696
|
-
parseDOM() {
|
|
25697
|
-
return [{ tag: 'span[data-id="auto-page-number"' }];
|
|
25698
|
-
},
|
|
25699
|
-
renderDOM({ htmlAttributes }) {
|
|
25700
|
-
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes)];
|
|
25701
|
-
},
|
|
25702
|
-
addCommands() {
|
|
25703
|
-
return {
|
|
25704
|
-
/**
|
|
25705
|
-
* Insert an automatic page number
|
|
25706
|
-
* @category Command
|
|
25707
|
-
* @returns {Function} Command function
|
|
25708
|
-
* @example
|
|
25709
|
-
* editor.commands.addAutoPageNumber()
|
|
25710
|
-
* @note Only works in header/footer contexts
|
|
25711
|
-
*/
|
|
25712
|
-
addAutoPageNumber: () => ({ tr, dispatch, state, editor }) => {
|
|
25713
|
-
const { options } = editor;
|
|
25714
|
-
if (!options.isHeaderOrFooter) return false;
|
|
25715
|
-
const { schema } = state;
|
|
25716
|
-
const pageNumberType = schema?.nodes?.["page-number"];
|
|
25717
|
-
if (!pageNumberType) return false;
|
|
25718
|
-
const pageNumberNodeJSON = { type: "page-number" };
|
|
25719
|
-
const pageNumberNode = schema.nodeFromJSON(pageNumberNodeJSON);
|
|
25720
|
-
if (dispatch) {
|
|
25721
|
-
tr.replaceSelectionWith(pageNumberNode, false);
|
|
25722
|
-
tr.setMeta("forceUpdatePagination", true);
|
|
25723
|
-
}
|
|
25724
|
-
return true;
|
|
25725
|
-
}
|
|
25726
|
-
};
|
|
25727
|
-
},
|
|
25728
|
-
addShortcuts() {
|
|
25729
|
-
return {
|
|
25730
|
-
"Mod-Shift-alt-p": () => this.editor.commands.addAutoPageNumber()
|
|
25731
|
-
};
|
|
25732
|
-
}
|
|
25733
|
-
});
|
|
25734
|
-
const TotalPageCount = Node$1.create({
|
|
25735
|
-
name: "total-page-number",
|
|
25736
|
-
group: "inline",
|
|
25737
|
-
inline: true,
|
|
25738
|
-
atom: true,
|
|
25739
|
-
draggable: false,
|
|
25740
|
-
selectable: false,
|
|
25741
|
-
content: "text*",
|
|
25742
|
-
addOptions() {
|
|
25743
|
-
return {
|
|
25744
|
-
htmlAttributes: {
|
|
25745
|
-
contenteditable: false,
|
|
25746
|
-
"data-id": "auto-total-pages",
|
|
25747
|
-
"aria-label": "Total page count node",
|
|
25748
|
-
class: "sd-editor-auto-total-pages"
|
|
25749
|
-
}
|
|
25750
|
-
};
|
|
25751
|
-
},
|
|
25752
|
-
addAttributes() {
|
|
25753
|
-
return {
|
|
25754
|
-
marksAsAttrs: {
|
|
25755
|
-
default: null,
|
|
25756
|
-
rendered: false
|
|
25757
|
-
}
|
|
25758
|
-
};
|
|
25759
|
-
},
|
|
25760
|
-
addNodeView() {
|
|
25761
|
-
return ({ node, editor, getPos, decorations }) => {
|
|
25762
|
-
const htmlAttributes = this.options.htmlAttributes;
|
|
25763
|
-
return new AutoPageNumberNodeView(node, getPos, decorations, editor, htmlAttributes);
|
|
25764
|
-
};
|
|
25765
|
-
},
|
|
25766
|
-
parseDOM() {
|
|
25767
|
-
return [{ tag: 'span[data-id="auto-total-pages"' }];
|
|
25768
|
-
},
|
|
25769
|
-
renderDOM({ htmlAttributes }) {
|
|
25770
|
-
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
25771
|
-
},
|
|
25772
|
-
addCommands() {
|
|
25773
|
-
return {
|
|
25774
|
-
/**
|
|
25775
|
-
* Insert total page count
|
|
25776
|
-
* @category Command
|
|
25777
|
-
* @returns {Function} Command function
|
|
25778
|
-
* @example
|
|
25779
|
-
* editor.commands.addTotalPageCount()
|
|
25780
|
-
* @note Only works in header/footer contexts
|
|
25781
|
-
*/
|
|
25782
|
-
addTotalPageCount: () => ({ tr, dispatch, state, editor }) => {
|
|
25783
|
-
const { options } = editor;
|
|
25784
|
-
if (!options.isHeaderOrFooter) return false;
|
|
25785
|
-
const { schema } = state;
|
|
25786
|
-
const pageNumberType = schema.nodes?.["total-page-number"];
|
|
25787
|
-
if (!pageNumberType) return false;
|
|
25788
|
-
const currentPages = editor?.options?.parentEditor?.currentTotalPages || 1;
|
|
25789
|
-
const pageNumberNode = {
|
|
25790
|
-
type: "total-page-number",
|
|
25791
|
-
content: [{ type: "text", text: String(currentPages) }]
|
|
25792
|
-
};
|
|
25793
|
-
const pageNode = schema.nodeFromJSON(pageNumberNode);
|
|
25794
|
-
if (dispatch) {
|
|
25795
|
-
tr.replaceSelectionWith(pageNode, false);
|
|
25796
|
-
}
|
|
25797
|
-
return true;
|
|
25798
|
-
}
|
|
25799
|
-
};
|
|
25800
|
-
},
|
|
25801
|
-
addShortcuts() {
|
|
25802
|
-
return {
|
|
25803
|
-
"Mod-Shift-alt-c": () => this.editor.commands.addTotalPageCount()
|
|
25804
|
-
};
|
|
25805
|
-
}
|
|
25806
|
-
});
|
|
25807
|
-
const getNodeAttributes = (nodeName, editor) => {
|
|
25808
|
-
switch (nodeName) {
|
|
25809
|
-
case "page-number":
|
|
25810
|
-
return {
|
|
25811
|
-
text: editor.options.currentPageNumber || "1",
|
|
25812
|
-
className: "sd-editor-auto-page-number",
|
|
25813
|
-
dataId: "auto-page-number",
|
|
25814
|
-
ariaLabel: "Page number node"
|
|
25815
|
-
};
|
|
25816
|
-
case "total-page-number":
|
|
25817
|
-
return {
|
|
25818
|
-
text: editor.options.parentEditor?.currentTotalPages || "1",
|
|
25819
|
-
className: "sd-editor-auto-total-pages",
|
|
25820
|
-
dataId: "auto-total-pages",
|
|
25821
|
-
ariaLabel: "Total page count node"
|
|
25822
|
-
};
|
|
25823
|
-
default:
|
|
25824
|
-
return {};
|
|
25825
|
-
}
|
|
25826
|
-
};
|
|
25827
|
-
class AutoPageNumberNodeView {
|
|
25828
|
-
constructor(node, getPos, decorations, editor, htmlAttributes = {}) {
|
|
25829
|
-
__privateAdd(this, _AutoPageNumberNodeView_instances);
|
|
25830
|
-
this.node = node;
|
|
25831
|
-
this.editor = editor;
|
|
25832
|
-
this.view = editor.view;
|
|
25833
|
-
this.getPos = getPos;
|
|
25834
|
-
this.editor = editor;
|
|
25835
|
-
this.dom = __privateMethod(this, _AutoPageNumberNodeView_instances, renderDom_fn).call(this, node, htmlAttributes);
|
|
25836
|
-
}
|
|
25837
|
-
update(node) {
|
|
25838
|
-
const incomingType = node?.type?.name;
|
|
25839
|
-
const currentType = this.node?.type?.name;
|
|
25840
|
-
if (!incomingType || incomingType !== currentType) return false;
|
|
25841
|
-
this.node = node;
|
|
25842
|
-
return true;
|
|
25843
|
-
}
|
|
25844
|
-
}
|
|
25845
|
-
_AutoPageNumberNodeView_instances = new WeakSet();
|
|
25846
|
-
renderDom_fn = function(node, htmlAttributes) {
|
|
25847
|
-
const attrs = getNodeAttributes(this.node.type.name, this.editor);
|
|
25848
|
-
const content = document.createTextNode(String(attrs.text));
|
|
25849
|
-
const nodeContent = document.createElement("span");
|
|
25850
|
-
nodeContent.className = attrs.className;
|
|
25851
|
-
nodeContent.setAttribute("data-id", attrs.dataId);
|
|
25852
|
-
nodeContent.setAttribute("aria-label", attrs.ariaLabel);
|
|
25853
|
-
const currentPos = this.getPos();
|
|
25854
|
-
const { styles, marks } = getMarksFromNeighbors(currentPos, this.view);
|
|
25855
|
-
__privateMethod(this, _AutoPageNumberNodeView_instances, scheduleUpdateNodeStyle_fn).call(this, currentPos, marks);
|
|
25856
|
-
Object.assign(nodeContent.style, styles);
|
|
25857
|
-
nodeContent.appendChild(content);
|
|
25858
|
-
Object.entries(htmlAttributes).forEach(([key2, value]) => {
|
|
25859
|
-
if (value) nodeContent.setAttribute(key2, value);
|
|
25860
|
-
});
|
|
25861
|
-
return nodeContent;
|
|
25862
|
-
};
|
|
25863
|
-
scheduleUpdateNodeStyle_fn = function(pos, marks) {
|
|
25864
|
-
setTimeout(() => {
|
|
25865
|
-
const { state } = this.editor;
|
|
25866
|
-
const { dispatch } = this.view;
|
|
25867
|
-
const node = state.doc.nodeAt(pos);
|
|
25868
|
-
if (!node || node.isText) return;
|
|
25869
|
-
const currentMarks = node.attrs.marksAsAttrs || [];
|
|
25870
|
-
const newMarks = marks.map((m) => ({ type: m.type.name, attrs: m.attrs }));
|
|
25871
|
-
const isEqual = JSON.stringify(currentMarks) === JSON.stringify(newMarks);
|
|
25872
|
-
if (isEqual) return;
|
|
25873
|
-
const newAttrs = {
|
|
25874
|
-
...node.attrs,
|
|
25875
|
-
marksAsAttrs: newMarks
|
|
25876
|
-
};
|
|
25877
|
-
const tr = state.tr.setNodeMarkup(pos, void 0, newAttrs);
|
|
25878
|
-
dispatch(tr);
|
|
25879
|
-
}, 0);
|
|
25880
|
-
};
|
|
25881
|
-
const getMarksFromNeighbors = (currentPos, view) => {
|
|
25882
|
-
const $pos = view.state.doc.resolve(currentPos);
|
|
25883
|
-
const styles = {};
|
|
25884
|
-
const marks = [];
|
|
25885
|
-
const before = $pos.nodeBefore;
|
|
25886
|
-
if (before) {
|
|
25887
|
-
Object.assign(styles, processMarks(before.marks));
|
|
25888
|
-
marks.push(...before.marks);
|
|
25889
|
-
}
|
|
25890
|
-
const after = $pos.nodeAfter;
|
|
25891
|
-
if (after) {
|
|
25892
|
-
Object.assign(styles, { ...styles, ...processMarks(after.marks) });
|
|
25893
|
-
marks.push(...after.marks);
|
|
25894
|
-
}
|
|
25895
|
-
return {
|
|
25896
|
-
styles,
|
|
25897
|
-
marks
|
|
25898
|
-
};
|
|
25899
|
-
};
|
|
25900
|
-
const processMarks = (marks) => {
|
|
25901
|
-
const styles = {};
|
|
25902
|
-
marks.forEach((mark) => {
|
|
25903
|
-
const { type, attrs } = mark;
|
|
25904
|
-
switch (type.name) {
|
|
25905
|
-
case "textStyle":
|
|
25906
|
-
if (attrs.fontFamily) styles["font-family"] = attrs.fontFamily;
|
|
25907
|
-
if (attrs.fontSize) styles["font-size"] = attrs.fontSize;
|
|
25908
|
-
if (attrs.color) styles["color"] = attrs.color;
|
|
25909
|
-
if (attrs.backgroundColor) styles["background-color"] = attrs.backgroundColor;
|
|
25910
|
-
break;
|
|
25911
|
-
case "bold":
|
|
25912
|
-
styles["font-weight"] = "bold";
|
|
25913
|
-
break;
|
|
25914
|
-
case "italic":
|
|
25915
|
-
styles["font-style"] = "italic";
|
|
25916
|
-
break;
|
|
25917
|
-
case "underline":
|
|
25918
|
-
styles["text-decoration"] = (styles["text-decoration"] || "") + " underline";
|
|
25919
|
-
break;
|
|
25920
|
-
case "strike":
|
|
25921
|
-
styles["text-decoration"] = (styles["text-decoration"] || "") + " line-through";
|
|
25922
|
-
break;
|
|
25923
|
-
default:
|
|
25924
|
-
if (attrs?.style) {
|
|
25925
|
-
Object.entries(attrs.style).forEach(([key2, value]) => {
|
|
25926
|
-
styles[key2] = value;
|
|
25927
|
-
});
|
|
25928
|
-
}
|
|
25929
|
-
break;
|
|
25930
|
-
}
|
|
25931
|
-
});
|
|
25932
|
-
return styles;
|
|
25933
|
-
};
|
|
25934
|
-
const ShapeContainer = Node$1.create({
|
|
25935
|
-
name: "shapeContainer",
|
|
25936
|
-
group: "block",
|
|
25937
|
-
content: "block+",
|
|
25938
|
-
isolating: true,
|
|
25939
|
-
addOptions() {
|
|
25940
|
-
return {
|
|
25941
|
-
htmlAttributes: {
|
|
25942
|
-
class: "sd-editor-shape-container",
|
|
25943
|
-
"aria-label": "Shape container node"
|
|
25944
|
-
}
|
|
25945
|
-
};
|
|
25946
|
-
},
|
|
25947
|
-
addAttributes() {
|
|
25948
|
-
return {
|
|
25949
|
-
fillcolor: {
|
|
25950
|
-
renderDOM: (attrs) => {
|
|
25951
|
-
if (!attrs.fillcolor) return {};
|
|
25952
|
-
return {
|
|
25953
|
-
style: `background-color: ${attrs.fillcolor}`
|
|
25954
|
-
};
|
|
25955
|
-
}
|
|
25956
|
-
},
|
|
25957
|
-
sdBlockId: {
|
|
25958
|
-
default: null,
|
|
25959
|
-
keepOnSplit: false,
|
|
25960
|
-
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
25961
|
-
renderDOM: (attrs) => {
|
|
25962
|
-
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
25963
|
-
}
|
|
25964
|
-
},
|
|
25965
|
-
style: {
|
|
25966
|
-
renderDOM: (attrs) => {
|
|
25967
|
-
if (!attrs.style) return {};
|
|
25968
|
-
return {
|
|
25969
|
-
style: attrs.style
|
|
25970
|
-
};
|
|
25971
|
-
}
|
|
25972
|
-
},
|
|
25973
|
-
wrapAttributes: {
|
|
25974
|
-
rendered: false
|
|
25975
|
-
},
|
|
25976
|
-
attributes: {
|
|
25977
|
-
rendered: false
|
|
25978
|
-
}
|
|
25979
|
-
};
|
|
25980
|
-
},
|
|
25981
|
-
parseDOM() {
|
|
25982
|
-
return [
|
|
25983
|
-
{
|
|
25984
|
-
tag: `div[data-type="${this.name}"]`
|
|
25985
|
-
}
|
|
25986
|
-
];
|
|
25987
|
-
},
|
|
25988
|
-
renderDOM({ htmlAttributes }) {
|
|
25989
|
-
return [
|
|
25990
|
-
"div",
|
|
25991
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
25992
|
-
0
|
|
25993
|
-
];
|
|
25994
|
-
}
|
|
25995
|
-
});
|
|
25996
|
-
const ShapeTextbox = Node$1.create({
|
|
25997
|
-
name: "shapeTextbox",
|
|
25998
|
-
group: "block",
|
|
25999
|
-
content: "paragraph* block*",
|
|
26000
|
-
isolating: true,
|
|
26001
|
-
addOptions() {
|
|
26002
|
-
return {
|
|
26003
|
-
htmlAttributes: {
|
|
26004
|
-
class: "sd-editor-shape-textbox",
|
|
26005
|
-
"aria-label": "Shape textbox node"
|
|
26006
|
-
}
|
|
26007
|
-
};
|
|
26008
|
-
},
|
|
26009
|
-
addAttributes() {
|
|
26010
|
-
return {
|
|
26011
|
-
sdBlockId: {
|
|
26012
|
-
default: null,
|
|
26013
|
-
keepOnSplit: false,
|
|
26014
|
-
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
26015
|
-
renderDOM: (attrs) => {
|
|
26016
|
-
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
26017
|
-
}
|
|
26018
|
-
},
|
|
26019
|
-
attributes: {
|
|
26020
|
-
rendered: false
|
|
26021
|
-
}
|
|
26022
|
-
};
|
|
26023
|
-
},
|
|
26024
|
-
parseDOM() {
|
|
26025
|
-
return [
|
|
26026
|
-
{
|
|
26027
|
-
tag: `div[data-type="${this.name}"]`
|
|
26028
|
-
}
|
|
26029
|
-
];
|
|
26030
|
-
},
|
|
26031
|
-
renderDOM({ htmlAttributes }) {
|
|
26032
|
-
return [
|
|
26033
|
-
"div",
|
|
26034
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
26035
|
-
0
|
|
26036
|
-
];
|
|
26037
|
-
}
|
|
26038
|
-
});
|
|
26039
|
-
const ContentBlock = Node$1.create({
|
|
26040
|
-
name: "contentBlock",
|
|
26041
|
-
group: "inline",
|
|
26042
|
-
content: "",
|
|
26043
|
-
isolating: true,
|
|
26044
|
-
atom: true,
|
|
26045
|
-
inline: true,
|
|
26046
|
-
addOptions() {
|
|
26047
|
-
return {
|
|
26048
|
-
htmlAttributes: {
|
|
26049
|
-
contenteditable: false
|
|
26050
|
-
}
|
|
26051
|
-
};
|
|
26052
|
-
},
|
|
26053
|
-
addAttributes() {
|
|
26054
|
-
return {
|
|
26055
|
-
horizontalRule: {
|
|
26056
|
-
default: false,
|
|
26057
|
-
renderDOM: ({ horizontalRule }) => {
|
|
26058
|
-
if (!horizontalRule) return {};
|
|
26059
|
-
return { "data-horizontal-rule": "true" };
|
|
26060
|
-
}
|
|
26061
|
-
},
|
|
26062
|
-
size: {
|
|
26063
|
-
default: null,
|
|
26064
|
-
renderDOM: ({ size }) => {
|
|
26065
|
-
if (!size) return {};
|
|
26066
|
-
let style = "";
|
|
26067
|
-
if (size.top) style += `top: ${size.top}px; `;
|
|
26068
|
-
if (size.left) style += `left: ${size.left}px; `;
|
|
26069
|
-
if (size.width) style += `width: ${size.width.toString().endsWith("%") ? size.width : `${size.width}px`}; `;
|
|
26070
|
-
if (size.height)
|
|
26071
|
-
style += `height: ${size.height.toString().endsWith("%") ? size.height : `${size.height}px`}; `;
|
|
26072
|
-
return { style };
|
|
26073
|
-
}
|
|
26074
|
-
},
|
|
26075
|
-
background: {
|
|
26076
|
-
default: null,
|
|
26077
|
-
renderDOM: (attrs) => {
|
|
26078
|
-
if (!attrs.background) return {};
|
|
26079
|
-
return {
|
|
26080
|
-
style: `background-color: ${attrs.background}`
|
|
26081
|
-
};
|
|
26082
|
-
}
|
|
26083
|
-
},
|
|
26084
|
-
drawingContent: {
|
|
26085
|
-
rendered: false
|
|
26086
|
-
},
|
|
26087
|
-
attributes: {
|
|
26720
|
+
addAttributes() {
|
|
26721
|
+
return {
|
|
26722
|
+
marksAsAttrs: {
|
|
26723
|
+
default: null,
|
|
26088
26724
|
rendered: false
|
|
26089
26725
|
}
|
|
26090
26726
|
};
|
|
26091
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
|
+
},
|
|
26092
26734
|
parseDOM() {
|
|
26093
|
-
return [
|
|
26094
|
-
{
|
|
26095
|
-
tag: `div[data-type="${this.name}"]`
|
|
26096
|
-
}
|
|
26097
|
-
];
|
|
26735
|
+
return [{ tag: 'span[data-id="auto-page-number"' }];
|
|
26098
26736
|
},
|
|
26099
26737
|
renderDOM({ htmlAttributes }) {
|
|
26100
|
-
return ["
|
|
26738
|
+
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes)];
|
|
26101
26739
|
},
|
|
26102
26740
|
addCommands() {
|
|
26103
26741
|
return {
|
|
26104
26742
|
/**
|
|
26105
|
-
* Insert
|
|
26106
|
-
* @category Command
|
|
26107
|
-
* @example
|
|
26108
|
-
* editor.commands.insertHorizontalRule()
|
|
26109
|
-
* @note Creates a visual separator between content sections
|
|
26110
|
-
*/
|
|
26111
|
-
insertHorizontalRule: () => ({ commands: commands2 }) => {
|
|
26112
|
-
return commands2.insertContent({
|
|
26113
|
-
type: this.name,
|
|
26114
|
-
attrs: {
|
|
26115
|
-
horizontalRule: true,
|
|
26116
|
-
size: { width: "100%", height: 2 },
|
|
26117
|
-
background: "#e5e7eb"
|
|
26118
|
-
}
|
|
26119
|
-
});
|
|
26120
|
-
},
|
|
26121
|
-
/**
|
|
26122
|
-
* Insert a content block
|
|
26743
|
+
* Insert an automatic page number
|
|
26123
26744
|
* @category Command
|
|
26124
|
-
* @
|
|
26125
|
-
* @example
|
|
26126
|
-
* // Insert a spacer block
|
|
26127
|
-
* editor.commands.insertContentBlock({ size: { height: 20 } })
|
|
26128
|
-
*
|
|
26745
|
+
* @returns {Function} Command function
|
|
26129
26746
|
* @example
|
|
26130
|
-
*
|
|
26131
|
-
*
|
|
26132
|
-
* size: { width: '50%', height: 3 },
|
|
26133
|
-
* background: '#3b82f6'
|
|
26134
|
-
* })
|
|
26135
|
-
* @note Used for spacing, dividers, and special inline content
|
|
26747
|
+
* editor.commands.addAutoPageNumber()
|
|
26748
|
+
* @note Only works in header/footer contexts
|
|
26136
26749
|
*/
|
|
26137
|
-
|
|
26138
|
-
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
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;
|
|
26142
26763
|
}
|
|
26143
26764
|
};
|
|
26765
|
+
},
|
|
26766
|
+
addShortcuts() {
|
|
26767
|
+
return {
|
|
26768
|
+
"Mod-Shift-alt-p": () => this.editor.commands.addAutoPageNumber()
|
|
26769
|
+
};
|
|
26144
26770
|
}
|
|
26145
26771
|
});
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
|
|
26149
|
-
__publicField(this, "view");
|
|
26150
|
-
__publicField(this, "getPos");
|
|
26151
|
-
__publicField(this, "decorations");
|
|
26152
|
-
__publicField(this, "innerDecorations");
|
|
26153
|
-
__publicField(this, "editor");
|
|
26154
|
-
__publicField(this, "extension");
|
|
26155
|
-
__publicField(this, "htmlAttributes");
|
|
26156
|
-
__publicField(this, "root");
|
|
26157
|
-
__publicField(this, "isDragging", false);
|
|
26158
|
-
this.node = props.node;
|
|
26159
|
-
this.view = props.editor.view;
|
|
26160
|
-
this.getPos = props.getPos;
|
|
26161
|
-
this.decorations = props.decorations;
|
|
26162
|
-
this.innerDecorations = props.innerDecorations;
|
|
26163
|
-
this.editor = props.editor;
|
|
26164
|
-
this.extension = props.extension;
|
|
26165
|
-
this.htmlAttributes = props.htmlAttributes;
|
|
26166
|
-
this.mount(props);
|
|
26167
|
-
}
|
|
26168
|
-
mount() {
|
|
26169
|
-
return;
|
|
26170
|
-
}
|
|
26171
|
-
get dom() {
|
|
26172
|
-
return this.root;
|
|
26173
|
-
}
|
|
26174
|
-
get contentDOM() {
|
|
26175
|
-
return null;
|
|
26176
|
-
}
|
|
26177
|
-
update(node, decorations, innerDecorations) {
|
|
26178
|
-
if (node.type !== this.node.type) {
|
|
26179
|
-
return false;
|
|
26180
|
-
}
|
|
26181
|
-
this.node = node;
|
|
26182
|
-
this.decorations = decorations;
|
|
26183
|
-
this.innerDecorations = innerDecorations;
|
|
26184
|
-
this.updateHTMLAttributes();
|
|
26185
|
-
return true;
|
|
26186
|
-
}
|
|
26187
|
-
stopEvent(event) {
|
|
26188
|
-
if (!this.dom) return false;
|
|
26189
|
-
const target = event.target;
|
|
26190
|
-
const isInElement = this.dom.contains(target) && !this.contentDOM?.contains(target);
|
|
26191
|
-
if (!isInElement) return false;
|
|
26192
|
-
const isDragEvent = event.type.startsWith("drag");
|
|
26193
|
-
const isDropEvent = event.type === "drop";
|
|
26194
|
-
const isInput = ["INPUT", "BUTTON", "SELECT", "TEXTAREA"].includes(target.tagName) || target.isContentEditable;
|
|
26195
|
-
if (isInput && !isDropEvent && !isDragEvent) return true;
|
|
26196
|
-
const { isEditable } = this.editor;
|
|
26197
|
-
const { isDragging } = this;
|
|
26198
|
-
const isDraggable = !!this.node.type.spec.draggable;
|
|
26199
|
-
const isSelectable = NodeSelection.isSelectable(this.node);
|
|
26200
|
-
const isCopyEvent = event.type === "copy";
|
|
26201
|
-
const isPasteEvent = event.type === "paste";
|
|
26202
|
-
const isCutEvent = event.type === "cut";
|
|
26203
|
-
const isClickEvent = event.type === "mousedown";
|
|
26204
|
-
if (!isDraggable && isSelectable && isDragEvent && event.target === this.dom) {
|
|
26205
|
-
event.preventDefault();
|
|
26206
|
-
}
|
|
26207
|
-
if (isDraggable && isDragEvent && !isDragging && event.target === this.dom) {
|
|
26208
|
-
event.preventDefault();
|
|
26209
|
-
return false;
|
|
26210
|
-
}
|
|
26211
|
-
if (isDraggable && isEditable && !isDragging && isClickEvent) {
|
|
26212
|
-
const dragHandle = target.closest("[data-drag-handle]");
|
|
26213
|
-
const isValidDragHandle = dragHandle && (this.dom === dragHandle || this.dom.contains(dragHandle));
|
|
26214
|
-
if (isValidDragHandle) {
|
|
26215
|
-
this.isDragging = true;
|
|
26216
|
-
document.addEventListener(
|
|
26217
|
-
"dragend",
|
|
26218
|
-
() => {
|
|
26219
|
-
this.isDragging = false;
|
|
26220
|
-
},
|
|
26221
|
-
{ once: true }
|
|
26222
|
-
);
|
|
26223
|
-
document.addEventListener(
|
|
26224
|
-
"drop",
|
|
26225
|
-
() => {
|
|
26226
|
-
this.isDragging = false;
|
|
26227
|
-
},
|
|
26228
|
-
{ once: true }
|
|
26229
|
-
);
|
|
26230
|
-
document.addEventListener(
|
|
26231
|
-
"mouseup",
|
|
26232
|
-
() => {
|
|
26233
|
-
this.isDragging = false;
|
|
26234
|
-
},
|
|
26235
|
-
{ once: true }
|
|
26236
|
-
);
|
|
26237
|
-
}
|
|
26238
|
-
}
|
|
26239
|
-
if (isDragging || isDropEvent || isCopyEvent || isPasteEvent || isCutEvent || isClickEvent && isSelectable) {
|
|
26240
|
-
return false;
|
|
26241
|
-
}
|
|
26242
|
-
return true;
|
|
26243
|
-
}
|
|
26244
|
-
ignoreMutation(mutation) {
|
|
26245
|
-
if (!this.dom || !this.contentDOM) return true;
|
|
26246
|
-
if (this.node.isLeaf || this.node.isAtom) return true;
|
|
26247
|
-
if (mutation.type === "selection") return false;
|
|
26248
|
-
if (this.contentDOM === mutation.target && mutation.type === "attributes") return true;
|
|
26249
|
-
if (this.contentDOM.contains(mutation.target)) return false;
|
|
26250
|
-
return true;
|
|
26251
|
-
}
|
|
26252
|
-
destroy() {
|
|
26253
|
-
this.dom.remove();
|
|
26254
|
-
this.contentDOM?.remove();
|
|
26255
|
-
}
|
|
26256
|
-
updateAttributes(attrs) {
|
|
26257
|
-
const pos = this.getPos();
|
|
26258
|
-
if (typeof pos !== "number") {
|
|
26259
|
-
return;
|
|
26260
|
-
}
|
|
26261
|
-
return this.view.dispatch(
|
|
26262
|
-
this.view.state.tr.setNodeMarkup(pos, void 0, {
|
|
26263
|
-
...this.node.attrs,
|
|
26264
|
-
...attrs
|
|
26265
|
-
})
|
|
26266
|
-
);
|
|
26267
|
-
}
|
|
26268
|
-
updateHTMLAttributes() {
|
|
26269
|
-
const { extensionService } = this.editor;
|
|
26270
|
-
const { attributes } = extensionService;
|
|
26271
|
-
const extensionAttrs = attributes.filter((i) => i.type === this.node.type.name);
|
|
26272
|
-
this.htmlAttributes = Attribute.getAttributesToRender(this.node, extensionAttrs);
|
|
26273
|
-
}
|
|
26274
|
-
createDragHandle() {
|
|
26275
|
-
const dragHandle = document.createElement("span");
|
|
26276
|
-
dragHandle.classList.add("sd-structured-content-draggable");
|
|
26277
|
-
dragHandle.draggable = true;
|
|
26278
|
-
dragHandle.contentEditable = "false";
|
|
26279
|
-
dragHandle.dataset.dragHandle = "";
|
|
26280
|
-
const textElement = document.createElement("span");
|
|
26281
|
-
textElement.textContent = "Structured content";
|
|
26282
|
-
dragHandle.append(textElement);
|
|
26283
|
-
return dragHandle;
|
|
26284
|
-
}
|
|
26285
|
-
onDragStart(event) {
|
|
26286
|
-
const { view } = this.editor;
|
|
26287
|
-
const target = event.target;
|
|
26288
|
-
const dragHandle = target.nodeType === 3 ? target.parentElement?.closest("[data-drag-handle]") : target.closest("[data-drag-handle]");
|
|
26289
|
-
if (!this.dom || this.contentDOM?.contains(target) || !dragHandle) {
|
|
26290
|
-
return;
|
|
26291
|
-
}
|
|
26292
|
-
let x = 0;
|
|
26293
|
-
let y = 0;
|
|
26294
|
-
if (this.dom !== dragHandle) {
|
|
26295
|
-
const domBox = this.dom.getBoundingClientRect();
|
|
26296
|
-
const handleBox = dragHandle.getBoundingClientRect();
|
|
26297
|
-
const offsetX = event.offsetX ?? event.nativeEvent?.offsetX;
|
|
26298
|
-
const offsetY = event.offsetY ?? event.nativeEvent?.offsetY;
|
|
26299
|
-
x = handleBox.x - domBox.x + offsetX;
|
|
26300
|
-
y = handleBox.y - domBox.y + offsetY;
|
|
26301
|
-
}
|
|
26302
|
-
event.dataTransfer?.setDragImage(this.dom, x, y);
|
|
26303
|
-
const pos = this.getPos();
|
|
26304
|
-
if (typeof pos !== "number") {
|
|
26305
|
-
return;
|
|
26306
|
-
}
|
|
26307
|
-
const selection = NodeSelection.create(view.state.doc, pos);
|
|
26308
|
-
const transaction = view.state.tr.setSelection(selection);
|
|
26309
|
-
view.dispatch(transaction);
|
|
26310
|
-
}
|
|
26311
|
-
}
|
|
26312
|
-
class StructuredContentInlineView extends StructuredContentViewBase {
|
|
26313
|
-
constructor(props) {
|
|
26314
|
-
super(props);
|
|
26315
|
-
}
|
|
26316
|
-
mount() {
|
|
26317
|
-
this.buildView();
|
|
26318
|
-
}
|
|
26319
|
-
get contentDOM() {
|
|
26320
|
-
const contentElement = this.dom?.querySelector(`.${structuredContentInnerClass$1}`);
|
|
26321
|
-
return contentElement || null;
|
|
26322
|
-
}
|
|
26323
|
-
createElement() {
|
|
26324
|
-
const element = document.createElement("span");
|
|
26325
|
-
element.classList.add(structuredContentClass$1);
|
|
26326
|
-
element.setAttribute("data-structured-content", "");
|
|
26327
|
-
const contentElement = document.createElement("span");
|
|
26328
|
-
contentElement.classList.add(structuredContentInnerClass$1);
|
|
26329
|
-
element.append(contentElement);
|
|
26330
|
-
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
26331
|
-
updateDOMAttributes(element, { ...domAttrs });
|
|
26332
|
-
return { element, contentElement };
|
|
26333
|
-
}
|
|
26334
|
-
buildView() {
|
|
26335
|
-
const { element } = this.createElement();
|
|
26336
|
-
const dragHandle = this.createDragHandle();
|
|
26337
|
-
element.prepend(dragHandle);
|
|
26338
|
-
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
26339
|
-
this.root = element;
|
|
26340
|
-
}
|
|
26341
|
-
updateView() {
|
|
26342
|
-
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
26343
|
-
updateDOMAttributes(this.dom, { ...domAttrs });
|
|
26344
|
-
}
|
|
26345
|
-
update(node, decorations, innerDecorations) {
|
|
26346
|
-
const result = super.update(node, decorations, innerDecorations);
|
|
26347
|
-
if (!result) return false;
|
|
26348
|
-
this.updateView();
|
|
26349
|
-
return true;
|
|
26350
|
-
}
|
|
26351
|
-
}
|
|
26352
|
-
const structuredContentClass$1 = "sd-structured-content";
|
|
26353
|
-
const structuredContentInnerClass$1 = "sd-structured-content__content";
|
|
26354
|
-
const StructuredContent = Node$1.create({
|
|
26355
|
-
name: "structuredContent",
|
|
26356
|
-
group: "inline structuredContent",
|
|
26772
|
+
const TotalPageCount = Node$1.create({
|
|
26773
|
+
name: "total-page-number",
|
|
26774
|
+
group: "inline",
|
|
26357
26775
|
inline: true,
|
|
26358
|
-
|
|
26359
|
-
|
|
26360
|
-
|
|
26361
|
-
|
|
26362
|
-
draggable: true,
|
|
26776
|
+
atom: true,
|
|
26777
|
+
draggable: false,
|
|
26778
|
+
selectable: false,
|
|
26779
|
+
content: "text*",
|
|
26363
26780
|
addOptions() {
|
|
26364
26781
|
return {
|
|
26365
26782
|
htmlAttributes: {
|
|
26366
|
-
|
|
26367
|
-
"
|
|
26783
|
+
contenteditable: false,
|
|
26784
|
+
"data-id": "auto-total-pages",
|
|
26785
|
+
"aria-label": "Total page count node",
|
|
26786
|
+
class: "sd-editor-auto-total-pages"
|
|
26368
26787
|
}
|
|
26369
26788
|
};
|
|
26370
26789
|
},
|
|
26371
26790
|
addAttributes() {
|
|
26372
26791
|
return {
|
|
26373
|
-
|
|
26792
|
+
marksAsAttrs: {
|
|
26374
26793
|
default: null,
|
|
26375
|
-
parseDOM: (elem) => elem.getAttribute("data-id"),
|
|
26376
|
-
renderDOM: (attrs) => {
|
|
26377
|
-
if (!attrs.id) return {};
|
|
26378
|
-
return { "data-id": attrs.id };
|
|
26379
|
-
}
|
|
26380
|
-
},
|
|
26381
|
-
sdtPr: {
|
|
26382
26794
|
rendered: false
|
|
26383
26795
|
}
|
|
26384
26796
|
};
|
|
26385
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
|
+
},
|
|
26386
26804
|
parseDOM() {
|
|
26387
|
-
return [{ tag:
|
|
26805
|
+
return [{ tag: 'span[data-id="auto-total-pages"' }];
|
|
26388
26806
|
},
|
|
26389
26807
|
renderDOM({ htmlAttributes }) {
|
|
26390
|
-
return [
|
|
26391
|
-
"span",
|
|
26392
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
|
|
26393
|
-
"data-structured-content": ""
|
|
26394
|
-
}),
|
|
26395
|
-
0
|
|
26396
|
-
];
|
|
26808
|
+
return ["span", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
26397
26809
|
},
|
|
26398
|
-
|
|
26399
|
-
return
|
|
26400
|
-
|
|
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()
|
|
26401
26842
|
};
|
|
26402
26843
|
}
|
|
26403
26844
|
});
|
|
26404
|
-
|
|
26405
|
-
|
|
26406
|
-
|
|
26407
|
-
|
|
26408
|
-
|
|
26409
|
-
|
|
26410
|
-
|
|
26411
|
-
|
|
26412
|
-
|
|
26413
|
-
|
|
26414
|
-
|
|
26415
|
-
|
|
26416
|
-
|
|
26417
|
-
|
|
26418
|
-
|
|
26419
|
-
|
|
26420
|
-
|
|
26421
|
-
|
|
26422
|
-
const domAttrs = Attribute.mergeAttributes(this.htmlAttributes);
|
|
26423
|
-
updateDOMAttributes(element, { ...domAttrs });
|
|
26424
|
-
return { element, contentElement };
|
|
26425
|
-
}
|
|
26426
|
-
buildView() {
|
|
26427
|
-
const { element } = this.createElement();
|
|
26428
|
-
const dragHandle = this.createDragHandle();
|
|
26429
|
-
element.prepend(dragHandle);
|
|
26430
|
-
element.addEventListener("dragstart", (e) => this.onDragStart(e));
|
|
26431
|
-
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 {};
|
|
26432
26863
|
}
|
|
26433
|
-
|
|
26434
|
-
|
|
26435
|
-
|
|
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);
|
|
26436
26874
|
}
|
|
26437
|
-
update(node
|
|
26438
|
-
const
|
|
26439
|
-
|
|
26440
|
-
|
|
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;
|
|
26441
26880
|
return true;
|
|
26442
26881
|
}
|
|
26443
26882
|
}
|
|
26444
|
-
|
|
26445
|
-
|
|
26446
|
-
const
|
|
26447
|
-
|
|
26448
|
-
|
|
26449
|
-
|
|
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+",
|
|
26450
26976
|
isolating: true,
|
|
26451
|
-
atom: false,
|
|
26452
|
-
// false - has editable content.
|
|
26453
|
-
draggable: true,
|
|
26454
26977
|
addOptions() {
|
|
26455
26978
|
return {
|
|
26456
26979
|
htmlAttributes: {
|
|
26457
|
-
class:
|
|
26458
|
-
"aria-label": "
|
|
26980
|
+
class: "sd-editor-shape-container",
|
|
26981
|
+
"aria-label": "Shape container node"
|
|
26459
26982
|
}
|
|
26460
26983
|
};
|
|
26461
26984
|
},
|
|
26462
26985
|
addAttributes() {
|
|
26463
26986
|
return {
|
|
26464
|
-
|
|
26987
|
+
fillcolor: {
|
|
26988
|
+
renderDOM: (attrs) => {
|
|
26989
|
+
if (!attrs.fillcolor) return {};
|
|
26990
|
+
return {
|
|
26991
|
+
style: `background-color: ${attrs.fillcolor}`
|
|
26992
|
+
};
|
|
26993
|
+
}
|
|
26994
|
+
},
|
|
26995
|
+
sdBlockId: {
|
|
26465
26996
|
default: null,
|
|
26466
|
-
|
|
26997
|
+
keepOnSplit: false,
|
|
26998
|
+
parseDOM: (elem) => elem.getAttribute("data-sd-block-id"),
|
|
26467
26999
|
renderDOM: (attrs) => {
|
|
26468
|
-
|
|
26469
|
-
return { "data-id": attrs.id };
|
|
27000
|
+
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
26470
27001
|
}
|
|
26471
27002
|
},
|
|
26472
|
-
|
|
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: {
|
|
26473
27015
|
rendered: false
|
|
26474
27016
|
}
|
|
26475
27017
|
};
|
|
26476
27018
|
},
|
|
26477
27019
|
parseDOM() {
|
|
26478
|
-
return [
|
|
27020
|
+
return [
|
|
27021
|
+
{
|
|
27022
|
+
tag: `div[data-type="${this.name}"]`
|
|
27023
|
+
}
|
|
27024
|
+
];
|
|
26479
27025
|
},
|
|
26480
27026
|
renderDOM({ htmlAttributes }) {
|
|
26481
27027
|
return [
|
|
26482
27028
|
"div",
|
|
26483
|
-
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, {
|
|
26484
|
-
"data-structured-content-block": ""
|
|
26485
|
-
}),
|
|
27029
|
+
Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes, { "data-type": this.name }),
|
|
26486
27030
|
0
|
|
26487
27031
|
];
|
|
26488
|
-
},
|
|
26489
|
-
addNodeView() {
|
|
26490
|
-
return (props) => {
|
|
26491
|
-
return new StructuredContentBlockView({ ...props });
|
|
26492
|
-
};
|
|
26493
27032
|
}
|
|
26494
27033
|
});
|
|
26495
|
-
|
|
26496
|
-
|
|
26497
|
-
__privateAdd(this, _DocumentSectionView_instances);
|
|
26498
|
-
this.node = node;
|
|
26499
|
-
this.editor = editor;
|
|
26500
|
-
this.decorations = decorations;
|
|
26501
|
-
this.view = editor.view;
|
|
26502
|
-
this.getPos = getPos;
|
|
26503
|
-
__privateMethod(this, _DocumentSectionView_instances, init_fn3).call(this);
|
|
26504
|
-
}
|
|
26505
|
-
}
|
|
26506
|
-
_DocumentSectionView_instances = new WeakSet();
|
|
26507
|
-
init_fn3 = function() {
|
|
26508
|
-
const { attrs } = this.node;
|
|
26509
|
-
const { id, title, description } = attrs;
|
|
26510
|
-
this.dom = document.createElement("div");
|
|
26511
|
-
this.dom.className = "sd-document-section-block";
|
|
26512
|
-
this.dom.setAttribute("data-id", id);
|
|
26513
|
-
this.dom.setAttribute("data-title", title);
|
|
26514
|
-
this.dom.setAttribute("data-description", description);
|
|
26515
|
-
this.dom.setAttribute("aria-label", "Document section");
|
|
26516
|
-
__privateMethod(this, _DocumentSectionView_instances, addToolTip_fn).call(this);
|
|
26517
|
-
this.contentDOM = document.createElement("div");
|
|
26518
|
-
this.contentDOM.className = "sd-document-section-block-content";
|
|
26519
|
-
this.contentDOM.setAttribute("contenteditable", "true");
|
|
26520
|
-
this.dom.appendChild(this.contentDOM);
|
|
26521
|
-
};
|
|
26522
|
-
addToolTip_fn = function() {
|
|
26523
|
-
const { title } = this.node.attrs;
|
|
26524
|
-
this.infoDiv = document.createElement("div");
|
|
26525
|
-
this.infoDiv.className = "sd-document-section-block-info";
|
|
26526
|
-
const textSpan = document.createElement("span");
|
|
26527
|
-
textSpan.textContent = title || "Document section";
|
|
26528
|
-
this.infoDiv.appendChild(textSpan);
|
|
26529
|
-
this.infoDiv.setAttribute("contenteditable", "false");
|
|
26530
|
-
this.dom.appendChild(this.infoDiv);
|
|
26531
|
-
};
|
|
26532
|
-
const getAllSections = (editor) => {
|
|
26533
|
-
if (!editor) return [];
|
|
26534
|
-
const type = editor.schema.nodes.documentSection;
|
|
26535
|
-
if (!type) return [];
|
|
26536
|
-
const sections = [];
|
|
26537
|
-
const { state } = editor;
|
|
26538
|
-
state.doc.descendants((node, pos) => {
|
|
26539
|
-
if (node.type.name === type.name) {
|
|
26540
|
-
sections.push({ node, pos });
|
|
26541
|
-
}
|
|
26542
|
-
});
|
|
26543
|
-
return sections;
|
|
26544
|
-
};
|
|
26545
|
-
const exportSectionsToHTML = (editor) => {
|
|
26546
|
-
const sections = getAllSections(editor);
|
|
26547
|
-
const processedSections = /* @__PURE__ */ new Set();
|
|
26548
|
-
const result = [];
|
|
26549
|
-
sections.forEach(({ node }) => {
|
|
26550
|
-
const { attrs } = node;
|
|
26551
|
-
const { id, title, description } = attrs;
|
|
26552
|
-
if (processedSections.has(id)) return;
|
|
26553
|
-
processedSections.add(id);
|
|
26554
|
-
const html = getHTMLFromNode(node, editor);
|
|
26555
|
-
result.push({
|
|
26556
|
-
id,
|
|
26557
|
-
title,
|
|
26558
|
-
description,
|
|
26559
|
-
html
|
|
26560
|
-
});
|
|
26561
|
-
});
|
|
26562
|
-
return result;
|
|
26563
|
-
};
|
|
26564
|
-
const getHTMLFromNode = (node, editor) => {
|
|
26565
|
-
const tempDocument = document.implementation.createHTMLDocument();
|
|
26566
|
-
const container = tempDocument.createElement("div");
|
|
26567
|
-
const fragment = DOMSerializer.fromSchema(editor.schema).serializeFragment(node.content);
|
|
26568
|
-
container.appendChild(fragment);
|
|
26569
|
-
let html = container.innerHTML;
|
|
26570
|
-
return html;
|
|
26571
|
-
};
|
|
26572
|
-
const exportSectionsToJSON = (editor) => {
|
|
26573
|
-
const sections = getAllSections(editor);
|
|
26574
|
-
const processedSections = /* @__PURE__ */ new Set();
|
|
26575
|
-
const result = [];
|
|
26576
|
-
sections.forEach(({ node }) => {
|
|
26577
|
-
const { attrs } = node;
|
|
26578
|
-
const { id, title, description } = attrs;
|
|
26579
|
-
if (processedSections.has(id)) return;
|
|
26580
|
-
processedSections.add(id);
|
|
26581
|
-
result.push({
|
|
26582
|
-
id,
|
|
26583
|
-
title,
|
|
26584
|
-
description,
|
|
26585
|
-
content: node.toJSON()
|
|
26586
|
-
});
|
|
26587
|
-
});
|
|
26588
|
-
return result;
|
|
26589
|
-
};
|
|
26590
|
-
const getLinkedSectionEditor = (id, options, editor) => {
|
|
26591
|
-
const sections = getAllSections(editor);
|
|
26592
|
-
const section = sections.find((s) => s.node.attrs.id === id);
|
|
26593
|
-
if (!section) return null;
|
|
26594
|
-
const child = editor.createChildEditor({
|
|
26595
|
-
...options,
|
|
26596
|
-
onUpdate: ({ editor: childEditor, transaction }) => {
|
|
26597
|
-
const isFromtLinkedParent = transaction.getMeta("fromLinkedParent");
|
|
26598
|
-
if (isFromtLinkedParent) return;
|
|
26599
|
-
const updatedContent = childEditor.state.doc.content;
|
|
26600
|
-
const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
|
|
26601
|
-
if (!sectionNode) return;
|
|
26602
|
-
const { pos, node } = sectionNode;
|
|
26603
|
-
const newNode = node.type.create(node.attrs, updatedContent, node.marks);
|
|
26604
|
-
const tr = editor.state.tr.replaceWith(pos, pos + node.nodeSize, newNode);
|
|
26605
|
-
tr.setMeta("fromLinkedChild", true);
|
|
26606
|
-
editor.view.dispatch(tr);
|
|
26607
|
-
}
|
|
26608
|
-
});
|
|
26609
|
-
editor.on("update", ({ transaction }) => {
|
|
26610
|
-
const isFromLinkedChild = transaction.getMeta("fromLinkedChild");
|
|
26611
|
-
if (isFromLinkedChild) return;
|
|
26612
|
-
const sectionNode = getAllSections(editor)?.find((s) => s.node.attrs.id === id);
|
|
26613
|
-
if (!sectionNode) return;
|
|
26614
|
-
const sectionContent = sectionNode.node.content;
|
|
26615
|
-
const json = {
|
|
26616
|
-
type: "doc",
|
|
26617
|
-
content: sectionContent.content.map((node) => node.toJSON())
|
|
26618
|
-
};
|
|
26619
|
-
const childTr = child.state.tr;
|
|
26620
|
-
childTr.setMeta("fromLinkedParent", true);
|
|
26621
|
-
childTr.replaceWith(0, child.state.doc.content.size, child.schema.nodeFromJSON(json));
|
|
26622
|
-
child.view.dispatch(childTr);
|
|
26623
|
-
});
|
|
26624
|
-
return child;
|
|
26625
|
-
};
|
|
26626
|
-
const SectionHelpers = {
|
|
26627
|
-
getAllSections,
|
|
26628
|
-
exportSectionsToHTML,
|
|
26629
|
-
exportSectionsToJSON,
|
|
26630
|
-
getLinkedSectionEditor
|
|
26631
|
-
};
|
|
26632
|
-
const DocumentSection = Node$1.create({
|
|
26633
|
-
name: "documentSection",
|
|
27034
|
+
const ShapeTextbox = Node$1.create({
|
|
27035
|
+
name: "shapeTextbox",
|
|
26634
27036
|
group: "block",
|
|
26635
|
-
content: "block*",
|
|
26636
|
-
atom: true,
|
|
27037
|
+
content: "paragraph* block*",
|
|
26637
27038
|
isolating: true,
|
|
26638
27039
|
addOptions() {
|
|
26639
27040
|
return {
|
|
26640
27041
|
htmlAttributes: {
|
|
26641
|
-
class: "sd-
|
|
26642
|
-
"aria-label": "
|
|
27042
|
+
class: "sd-editor-shape-textbox",
|
|
27043
|
+
"aria-label": "Shape textbox node"
|
|
26643
27044
|
}
|
|
26644
27045
|
};
|
|
26645
27046
|
},
|
|
26646
|
-
parseDOM() {
|
|
26647
|
-
return [
|
|
26648
|
-
{
|
|
26649
|
-
tag: "div.sd-document-section-block",
|
|
26650
|
-
priority: 60
|
|
26651
|
-
}
|
|
26652
|
-
];
|
|
26653
|
-
},
|
|
26654
|
-
renderDOM({ htmlAttributes }) {
|
|
26655
|
-
return ["div", Attribute.mergeAttributes(this.options.htmlAttributes, htmlAttributes), 0];
|
|
26656
|
-
},
|
|
26657
27047
|
addAttributes() {
|
|
26658
27048
|
return {
|
|
26659
|
-
id: {},
|
|
26660
27049
|
sdBlockId: {
|
|
26661
27050
|
default: null,
|
|
26662
27051
|
keepOnSplit: false,
|
|
@@ -26665,212 +27054,131 @@ const DocumentSection = Node$1.create({
|
|
|
26665
27054
|
return attrs.sdBlockId ? { "data-sd-block-id": attrs.sdBlockId } : {};
|
|
26666
27055
|
}
|
|
26667
27056
|
},
|
|
26668
|
-
|
|
26669
|
-
|
|
26670
|
-
|
|
26671
|
-
isLocked: { default: false }
|
|
27057
|
+
attributes: {
|
|
27058
|
+
rendered: false
|
|
27059
|
+
}
|
|
26672
27060
|
};
|
|
26673
27061
|
},
|
|
26674
|
-
|
|
26675
|
-
return
|
|
26676
|
-
|
|
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
|
+
}
|
|
26677
27089
|
};
|
|
26678
27090
|
},
|
|
26679
|
-
|
|
27091
|
+
addAttributes() {
|
|
26680
27092
|
return {
|
|
26681
|
-
|
|
26682
|
-
|
|
26683
|
-
|
|
26684
|
-
|
|
26685
|
-
|
|
26686
|
-
* editor.commands.createDocumentSection({
|
|
26687
|
-
* id: 1,
|
|
26688
|
-
* title: 'Terms & Conditions',
|
|
26689
|
-
* isLocked: true,
|
|
26690
|
-
* html: '<p>Legal content...</p>'
|
|
26691
|
-
* })
|
|
26692
|
-
*/
|
|
26693
|
-
createDocumentSection: (options = {}) => ({ tr, state, dispatch, editor }) => {
|
|
26694
|
-
const { selection } = state;
|
|
26695
|
-
let { from: from2, to } = selection;
|
|
26696
|
-
let content = selection.content().content;
|
|
26697
|
-
const { html: optionsHTML, json: optionsJSON } = options;
|
|
26698
|
-
if (optionsHTML) {
|
|
26699
|
-
const html = htmlHandler(optionsHTML, this.editor);
|
|
26700
|
-
const doc2 = DOMParser$1.fromSchema(this.editor.schema).parse(html);
|
|
26701
|
-
content = doc2.content;
|
|
26702
|
-
}
|
|
26703
|
-
if (optionsJSON) {
|
|
26704
|
-
content = this.editor.schema.nodeFromJSON(optionsJSON);
|
|
26705
|
-
}
|
|
26706
|
-
if (!content?.content?.length) {
|
|
26707
|
-
content = this.editor.schema.nodeFromJSON({ type: "paragraph", content: [] });
|
|
26708
|
-
}
|
|
26709
|
-
if (!options.id) {
|
|
26710
|
-
const allSections = SectionHelpers.getAllSections(editor);
|
|
26711
|
-
options.id = allSections.length + 1;
|
|
26712
|
-
}
|
|
26713
|
-
if (!options.title) {
|
|
26714
|
-
options.title = "Document section";
|
|
26715
|
-
}
|
|
26716
|
-
const node = this.type.createAndFill(options, content);
|
|
26717
|
-
if (!node) return false;
|
|
26718
|
-
const isAlreadyInSdtBlock = findParentNode((node2) => node2.type.name === "documentSection")(selection);
|
|
26719
|
-
if (isAlreadyInSdtBlock && isAlreadyInSdtBlock.node) {
|
|
26720
|
-
const insertPos2 = isAlreadyInSdtBlock.pos + isAlreadyInSdtBlock.node.nodeSize;
|
|
26721
|
-
from2 = insertPos2;
|
|
26722
|
-
to = insertPos2;
|
|
26723
|
-
}
|
|
26724
|
-
tr.replaceRangeWith(from2, to, node);
|
|
26725
|
-
const nodeEnd = from2 + node.nodeSize;
|
|
26726
|
-
let shouldInsertParagraph = true;
|
|
26727
|
-
let insertPos = nodeEnd;
|
|
26728
|
-
if (nodeEnd >= tr.doc.content.size) {
|
|
26729
|
-
insertPos = tr.doc.content.size;
|
|
26730
|
-
if (insertPos > 0) {
|
|
26731
|
-
const $endPos = tr.doc.resolve(insertPos);
|
|
26732
|
-
if ($endPos.nodeBefore && $endPos.nodeBefore.type.name === "paragraph") {
|
|
26733
|
-
shouldInsertParagraph = false;
|
|
26734
|
-
}
|
|
26735
|
-
}
|
|
26736
|
-
}
|
|
26737
|
-
if (shouldInsertParagraph) {
|
|
26738
|
-
const emptyParagraph = tr.doc.type.schema.nodes.paragraph.create();
|
|
26739
|
-
tr.insert(insertPos, emptyParagraph);
|
|
26740
|
-
}
|
|
26741
|
-
if (dispatch) {
|
|
26742
|
-
tr.setMeta("documentSection", { action: "create" });
|
|
26743
|
-
dispatch(tr);
|
|
26744
|
-
setTimeout(() => {
|
|
26745
|
-
try {
|
|
26746
|
-
const currentState = editor.state;
|
|
26747
|
-
const docSize = currentState.doc.content.size;
|
|
26748
|
-
let targetPos = from2 + node.nodeSize;
|
|
26749
|
-
if (shouldInsertParagraph) {
|
|
26750
|
-
targetPos += 1;
|
|
26751
|
-
}
|
|
26752
|
-
targetPos = Math.min(targetPos, docSize);
|
|
26753
|
-
if (targetPos < docSize && targetPos > 0) {
|
|
26754
|
-
const newSelection = Selection.near(currentState.doc.resolve(targetPos));
|
|
26755
|
-
const newTr = currentState.tr.setSelection(newSelection);
|
|
26756
|
-
editor.view.dispatch(newTr);
|
|
26757
|
-
}
|
|
26758
|
-
} catch (e) {
|
|
26759
|
-
console.warn("Could not set delayed selection:", e);
|
|
26760
|
-
}
|
|
26761
|
-
}, 0);
|
|
27093
|
+
horizontalRule: {
|
|
27094
|
+
default: false,
|
|
27095
|
+
renderDOM: ({ horizontalRule }) => {
|
|
27096
|
+
if (!horizontalRule) return {};
|
|
27097
|
+
return { "data-horizontal-rule": "true" };
|
|
26762
27098
|
}
|
|
26763
|
-
return true;
|
|
26764
27099
|
},
|
|
26765
|
-
|
|
26766
|
-
|
|
26767
|
-
|
|
26768
|
-
|
|
26769
|
-
|
|
26770
|
-
|
|
26771
|
-
|
|
26772
|
-
|
|
26773
|
-
|
|
26774
|
-
|
|
26775
|
-
|
|
26776
|
-
const nodeStart = pos;
|
|
26777
|
-
const nodeEnd = nodeStart + node.nodeSize;
|
|
26778
|
-
const contentToPreserve = node.content;
|
|
26779
|
-
tr.delete(nodeStart, nodeEnd);
|
|
26780
|
-
if (contentToPreserve.size > 0) {
|
|
26781
|
-
tr.insert(nodeStart, contentToPreserve);
|
|
26782
|
-
}
|
|
26783
|
-
const newPos = Math.min(nodeStart, tr.doc.content.size);
|
|
26784
|
-
tr.setSelection(Selection.near(tr.doc.resolve(newPos)));
|
|
26785
|
-
if (dispatch) {
|
|
26786
|
-
tr.setMeta("documentSection", { action: "delete" });
|
|
26787
|
-
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 };
|
|
26788
27111
|
}
|
|
26789
|
-
return true;
|
|
26790
27112
|
},
|
|
26791
|
-
|
|
26792
|
-
|
|
26793
|
-
|
|
26794
|
-
|
|
26795
|
-
|
|
26796
|
-
|
|
26797
|
-
|
|
26798
|
-
removeSectionById: (id) => ({ tr, dispatch }) => {
|
|
26799
|
-
const sections = SectionHelpers.getAllSections(this.editor);
|
|
26800
|
-
const sectionToRemove = sections.find(({ node: node2 }) => node2.attrs.id === id);
|
|
26801
|
-
if (!sectionToRemove) return false;
|
|
26802
|
-
const { pos, node } = sectionToRemove;
|
|
26803
|
-
const nodeStart = pos;
|
|
26804
|
-
const nodeEnd = nodeStart + node.nodeSize;
|
|
26805
|
-
tr.delete(nodeStart, nodeEnd);
|
|
26806
|
-
if (dispatch) {
|
|
26807
|
-
tr.setMeta("documentSection", { action: "delete", id });
|
|
26808
|
-
dispatch(tr);
|
|
27113
|
+
background: {
|
|
27114
|
+
default: null,
|
|
27115
|
+
renderDOM: (attrs) => {
|
|
27116
|
+
if (!attrs.background) return {};
|
|
27117
|
+
return {
|
|
27118
|
+
style: `background-color: ${attrs.background}`
|
|
27119
|
+
};
|
|
26809
27120
|
}
|
|
26810
|
-
return true;
|
|
26811
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 {
|
|
26812
27142
|
/**
|
|
26813
|
-
*
|
|
27143
|
+
* Insert a horizontal rule
|
|
26814
27144
|
* @category Command
|
|
26815
|
-
* @param {number} id - Section to lock
|
|
26816
27145
|
* @example
|
|
26817
|
-
* editor.commands.
|
|
27146
|
+
* editor.commands.insertHorizontalRule()
|
|
27147
|
+
* @note Creates a visual separator between content sections
|
|
26818
27148
|
*/
|
|
26819
|
-
|
|
26820
|
-
|
|
26821
|
-
|
|
26822
|
-
|
|
26823
|
-
|
|
26824
|
-
|
|
26825
|
-
|
|
26826
|
-
|
|
26827
|
-
}
|
|
26828
|
-
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
|
+
});
|
|
26829
27158
|
},
|
|
26830
27159
|
/**
|
|
26831
|
-
*
|
|
27160
|
+
* Insert a content block
|
|
26832
27161
|
* @category Command
|
|
26833
|
-
* @param {
|
|
27162
|
+
* @param {ContentBlockConfig} config - Block configuration
|
|
26834
27163
|
* @example
|
|
26835
|
-
*
|
|
26836
|
-
* editor.commands.
|
|
26837
|
-
*
|
|
26838
|
-
*
|
|
26839
|
-
*
|
|
26840
|
-
*
|
|
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'
|
|
26841
27172
|
* })
|
|
27173
|
+
* @note Used for spacing, dividers, and special inline content
|
|
26842
27174
|
*/
|
|
26843
|
-
|
|
26844
|
-
|
|
26845
|
-
|
|
26846
|
-
|
|
26847
|
-
|
|
26848
|
-
let newContent = null;
|
|
26849
|
-
if (html) {
|
|
26850
|
-
const htmlDoc = htmlHandler(html, editor || this.editor);
|
|
26851
|
-
const doc2 = DOMParser$1.fromSchema((editor || this.editor).schema).parse(htmlDoc);
|
|
26852
|
-
newContent = doc2.content;
|
|
26853
|
-
}
|
|
26854
|
-
if (json) {
|
|
26855
|
-
newContent = (editor || this.editor).schema.nodeFromJSON(json);
|
|
26856
|
-
}
|
|
26857
|
-
if (!newContent) {
|
|
26858
|
-
newContent = node.content;
|
|
26859
|
-
}
|
|
26860
|
-
const updatedNode = node.type.create({ ...node.attrs, ...attrs }, newContent, node.marks);
|
|
26861
|
-
tr.replaceWith(pos, pos + node.nodeSize, updatedNode);
|
|
26862
|
-
if (dispatch) {
|
|
26863
|
-
tr.setMeta("documentSection", { action: "update", id, attrs });
|
|
26864
|
-
dispatch(tr);
|
|
26865
|
-
}
|
|
26866
|
-
return true;
|
|
27175
|
+
insertContentBlock: (config) => ({ commands: commands2 }) => {
|
|
27176
|
+
return commands2.insertContent({
|
|
27177
|
+
type: this.name,
|
|
27178
|
+
attrs: config
|
|
27179
|
+
});
|
|
26867
27180
|
}
|
|
26868
27181
|
};
|
|
26869
|
-
},
|
|
26870
|
-
addHelpers() {
|
|
26871
|
-
return {
|
|
26872
|
-
...SectionHelpers
|
|
26873
|
-
};
|
|
26874
27182
|
}
|
|
26875
27183
|
});
|
|
26876
27184
|
const { findChildren } = helpers;
|
|
@@ -33438,7 +33746,8 @@ const nodeResizer = (nodeNames = ["image"], editor) => {
|
|
|
33438
33746
|
const prevSelection = prevState.selection;
|
|
33439
33747
|
if (selection.from !== prevSelection.from || selection.to !== prevSelection.to) {
|
|
33440
33748
|
setTimeout(() => {
|
|
33441
|
-
const
|
|
33749
|
+
const searchRoot = editorView?.dom;
|
|
33750
|
+
const selectedResizableWrapper = searchRoot?.querySelector(".sd-editor-resizable-wrapper");
|
|
33442
33751
|
if (selectedResizableWrapper) {
|
|
33443
33752
|
showResizeHandles(view2, selectedResizableWrapper);
|
|
33444
33753
|
} else {
|
|
@@ -33719,6 +34028,7 @@ const getStarterExtensions = () => {
|
|
|
33719
34028
|
Search,
|
|
33720
34029
|
StructuredContent,
|
|
33721
34030
|
StructuredContentBlock,
|
|
34031
|
+
StructuredContentCommands,
|
|
33722
34032
|
DocumentSection,
|
|
33723
34033
|
NodeResizer,
|
|
33724
34034
|
CustomSelection,
|
|
@@ -33752,6 +34062,7 @@ export {
|
|
|
33752
34062
|
SectionHelpers as o,
|
|
33753
34063
|
getAllowedImageDimensions as p,
|
|
33754
34064
|
replaceSelectionWithImagePlaceholder as r,
|
|
34065
|
+
shouldBypassContextMenu as s,
|
|
33755
34066
|
useHighContrastMode as u,
|
|
33756
34067
|
yUndoPluginKey as y
|
|
33757
34068
|
};
|