@stll/folio-core 0.61.0 → 0.62.0
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/ai-edits/headless.js +13 -12
- package/dist/controller/noteEditorManager.d.ts +1 -1
- package/dist/display-list/build/imagePrimitives.js +26 -7
- package/dist/display-list/build/paragraphPrimitives.js +15 -2
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -5
- package/dist/display-list/types.d.ts +7 -3
- package/dist/docx/groupDrawingParser.js +22 -12
- package/dist/i18n/messages/ar.gen.js +1 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/cs.gen.js +1 -0
- package/dist/i18n/messages/de.gen.js +1 -0
- package/dist/i18n/messages/en.gen.js +1 -0
- package/dist/i18n/messages/es.gen.js +1 -0
- package/dist/i18n/messages/et.gen.js +1 -0
- package/dist/i18n/messages/fr.gen.js +1 -0
- package/dist/i18n/messages/he.gen.js +1 -0
- package/dist/i18n/messages/hi.gen.js +1 -0
- package/dist/i18n/messages/hu.gen.js +1 -0
- package/dist/i18n/messages/lt.gen.js +1 -0
- package/dist/i18n/messages/lv.gen.js +1 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/i18n/messages/pl.gen.js +1 -0
- package/dist/i18n/messages/pt-BR.gen.js +1 -0
- package/dist/i18n/messages/sk.gen.js +1 -0
- package/dist/i18n/messages/tr.gen.js +1 -0
- package/dist/i18n/messages/zh-CN.gen.js +1 -0
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +1 -1
- package/dist/layout-bridge/convert/endnoteLayout.js +1 -3
- package/dist/layout-engine/index.js +2 -2
- package/dist/layout-engine/noteAreaFlow.d.ts +4 -4
- package/dist/layout-engine/noteAreaFlow.js +12 -6
- package/dist/layout-engine/types.d.ts +5 -2
- package/dist/layout-painter/index.d.ts +1 -1
- package/dist/managers/FindReplaceManager.d.ts +13 -6
- package/dist/managers/FindReplaceManager.js +15 -9
- package/dist/paged-layout/editorScrollRoot.d.ts +3 -1
- package/dist/paged-layout/editorScrollRoot.js +2 -2
- package/dist/pdf/images.js +1 -0
- package/dist/prosemirror/commentRangeInlineAtoms.d.ts +40 -0
- package/dist/prosemirror/commentRangeInlineAtoms.js +33 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +5 -4
- package/dist/prosemirror/conversion/toProseDoc.js +12 -19
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +4 -4
- package/dist/prosemirror/fieldRepresentation.js +4 -2
- package/dist/prosemirror/findReplaceSelection.d.ts +38 -2
- package/dist/prosemirror/findReplaceSelection.js +143 -42
- package/dist/prosemirror/inlineDisplayText.d.ts +10 -0
- package/dist/prosemirror/inlineDisplayText.js +29 -0
- package/dist/prosemirror/trackedRunInlineAtoms.d.ts +1 -1
- package/dist/prosemirror/trackedRunInlineAtoms.js +1 -1
- package/dist/utils/findMatchView.d.ts +32 -0
- package/dist/utils/findMatchView.js +406 -0
- package/dist/utils/findReplace.d.ts +62 -4
- package/dist/utils/findReplace.js +359 -37
- package/dist/utils/findSearchKey.d.ts +29 -0
- package/dist/utils/findSearchKey.js +34 -0
- package/dist/utils/replaceText.js +138 -111
- package/package.json +1 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import "./extensions/marks/InlineWrapperExtension.js";
|
|
2
|
+
import { getInlineDisplayText } from "./inlineDisplayText.js";
|
|
2
3
|
//#region src/prosemirror/fieldRepresentation.ts
|
|
3
4
|
/** Current children alone decide whether a field needs editable structural content. */
|
|
4
5
|
const fieldRequiresStructuredContent = (children) => children.some((child) => !child.isText || child.marks.some((mark) => mark.type.name === "hyperlink" || mark.type.name === "inlineWrapper" || mark.type.name === "insertion" || mark.type.name === "deletion"));
|
|
5
6
|
/** Resolution returns text-only fields to the same atom representation as initial conversion. */
|
|
6
7
|
const canonicalFieldNode = (node) => {
|
|
7
8
|
if (node.type.name !== "structuredField") return node;
|
|
9
|
+
const displayText = getInlineDisplayText(node);
|
|
8
10
|
const attrs = {
|
|
9
11
|
...node.attrs,
|
|
10
|
-
displayText
|
|
12
|
+
displayText
|
|
11
13
|
};
|
|
12
|
-
if (fieldRequiresStructuredContent(node.content.content)) return node.attrs["displayText"] ===
|
|
14
|
+
if (fieldRequiresStructuredContent(node.content.content)) return node.attrs["displayText"] === displayText ? node : node.type.create(attrs, node.content, node.marks);
|
|
13
15
|
let marks = node.marks;
|
|
14
16
|
for (const mark of node.firstChild?.marks ?? []) marks = mark.addToSet(marks);
|
|
15
17
|
return node.type.schema.node("field", attrs, void 0, marks);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
1
2
|
import { DisplayMode } from "../managers/EditorModeManager.js";
|
|
2
|
-
import { FindOptions } from "../utils/findReplace.js";
|
|
3
|
+
import { FindMatch, FindOptions, FindSearchContext } from "../utils/findReplace.js";
|
|
3
4
|
import { Node } from "prosemirror-model";
|
|
4
5
|
import { EditorState } from "prosemirror-state";
|
|
5
6
|
//#region src/prosemirror/findReplaceSelection.d.ts
|
|
@@ -22,11 +23,25 @@ type FindMatchPosition = {
|
|
|
22
23
|
type FindMatchRange = {
|
|
23
24
|
from: number;
|
|
24
25
|
to: number;
|
|
26
|
+
/** Navigation anchors inside a logical match are excluded from decorations. */
|
|
27
|
+
excludedRanges?: {
|
|
28
|
+
from: number;
|
|
29
|
+
to: number;
|
|
30
|
+
}[];
|
|
31
|
+
/** Character subranges inside source atoms, whose text exceeds their PM size. */
|
|
32
|
+
atomicTextRanges?: {
|
|
33
|
+
from: number;
|
|
34
|
+
to: number;
|
|
35
|
+
startOffset: number;
|
|
36
|
+
endOffset: number;
|
|
37
|
+
}[];
|
|
25
38
|
};
|
|
26
39
|
type ProseMirrorFindMatch = FindMatchPosition & FindMatchRange & {
|
|
27
40
|
text: string;
|
|
28
41
|
};
|
|
29
42
|
declare function resolveFindMatchRange(doc: Node, match: FindMatchPosition): FindMatchRange | null;
|
|
43
|
+
/** Resolve a result set in one paragraph traversal, preserving result order. */
|
|
44
|
+
declare const resolveFindMatchRanges: (doc: Node, matches: readonly FindMatchPosition[]) => (FindMatchRange | null)[];
|
|
30
45
|
declare function findInProseMirrorDocument(doc: Node, searchText: string, options: FindOptions): ProseMirrorFindMatch[];
|
|
31
46
|
type FindInMarkupViewOptions = {
|
|
32
47
|
state: EditorState;
|
|
@@ -36,5 +51,26 @@ type FindInMarkupViewOptions = {
|
|
|
36
51
|
};
|
|
37
52
|
/** Search the displayed story; returned ranges address the authored editor document. */
|
|
38
53
|
declare const findInMarkupView: ({ state, markupView, searchText, options }: FindInMarkupViewOptions) => ProseMirrorFindMatch[];
|
|
54
|
+
type FindInDisplayedDocumentOptions = {
|
|
55
|
+
document: document_d_exports.Document;
|
|
56
|
+
/**
|
|
57
|
+
* Live body editor state. A review view reads its body from this state's
|
|
58
|
+
* projection, so null defers that search until the body editor mounts.
|
|
59
|
+
* Hosts without an editor state omit it and search the package model.
|
|
60
|
+
*/
|
|
61
|
+
state?: EditorState | null | undefined;
|
|
62
|
+
searchText: string;
|
|
63
|
+
options: FindOptions;
|
|
64
|
+
context?: FindSearchContext | undefined;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Search every story a display mode shows. All Markup searches the package
|
|
68
|
+
* stories. A resolved review view searches its body through the projection the
|
|
69
|
+
* layout paints, so body ranges address the authored editor document; anchored
|
|
70
|
+
* shapes, headers, footers, notes and comments keep the package search owner
|
|
71
|
+
* with the same display mode. Returns null while a review view has no body
|
|
72
|
+
* editor state to project.
|
|
73
|
+
*/
|
|
74
|
+
declare const findInDisplayedDocument: ({ document, state, searchText, options, context }: FindInDisplayedDocumentOptions) => FindMatch[] | null;
|
|
39
75
|
//#endregion
|
|
40
|
-
export { FindMatchPosition, FindMatchRange, ProseMirrorFindMatch, findInMarkupView, findInProseMirrorDocument, resolveFindMatchRange };
|
|
76
|
+
export { FindMatchPosition, FindMatchRange, ProseMirrorFindMatch, findInDisplayedDocument, findInMarkupView, findInProseMirrorDocument, resolveFindMatchRange, resolveFindMatchRanges };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { findAllMatches } from "../utils/findReplace.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { findAllMatches, findInDocument, isPageDependentSearchField } from "../utils/findReplace.js";
|
|
2
|
+
import { expectFieldAttrs } from "./attrs/index.js";
|
|
3
|
+
import { getInlineDisplayText, getInlineDisplayToken, isNoteReferenceText } from "./inlineDisplayText.js";
|
|
4
4
|
import { projectMarkupView } from "./markupViewProjection.js";
|
|
5
5
|
//#region src/prosemirror/findReplaceSelection.ts
|
|
6
6
|
function resolveFindMatchRange(doc, match) {
|
|
@@ -17,11 +17,29 @@ function resolveFindMatchRange(doc, match) {
|
|
|
17
17
|
});
|
|
18
18
|
return resolved;
|
|
19
19
|
}
|
|
20
|
+
/** Resolve a result set in one paragraph traversal, preserving result order. */
|
|
21
|
+
const resolveFindMatchRanges = (doc, matches) => {
|
|
22
|
+
const paragraphs = /* @__PURE__ */ new Map();
|
|
23
|
+
forEachSearchParagraph(doc, (paragraph, paragraphPos, paragraphIndex) => {
|
|
24
|
+
paragraphs.set(paragraphIndex, {
|
|
25
|
+
paragraph,
|
|
26
|
+
paragraphPos
|
|
27
|
+
});
|
|
28
|
+
return true;
|
|
29
|
+
});
|
|
30
|
+
return matches.map((match) => {
|
|
31
|
+
const paragraph = paragraphs.get(match.paragraphIndex);
|
|
32
|
+
return paragraph ? resolveTextRangeInParagraph({
|
|
33
|
+
...paragraph,
|
|
34
|
+
...match
|
|
35
|
+
}) : null;
|
|
36
|
+
});
|
|
37
|
+
};
|
|
20
38
|
function findInProseMirrorDocument(doc, searchText, options) {
|
|
21
39
|
if (!searchText) return [];
|
|
22
40
|
const matches = [];
|
|
23
41
|
forEachSearchParagraph(doc, (paragraph, paragraphPos, paragraphIndex) => {
|
|
24
|
-
const text =
|
|
42
|
+
const text = getInlineDisplayText(paragraph);
|
|
25
43
|
for (const { start, end } of findAllMatches(text, searchText, options)) {
|
|
26
44
|
const range = resolveTextRangeInParagraph({
|
|
27
45
|
paragraph,
|
|
@@ -45,14 +63,95 @@ function findInProseMirrorDocument(doc, searchText, options) {
|
|
|
45
63
|
const findInMarkupView = ({ state, markupView, searchText, options }) => {
|
|
46
64
|
const projection = projectMarkupView(state, markupView);
|
|
47
65
|
if (projection.type === "authored") return findInProseMirrorDocument(state.doc, searchText, options);
|
|
48
|
-
return findInProseMirrorDocument(projection.doc, searchText, options).map((match) => (
|
|
66
|
+
return findInProseMirrorDocument(projection.doc, searchText, options).map((match) => toAuthoredFindMatch(projection, match));
|
|
67
|
+
};
|
|
68
|
+
/** Every view-document position a match carries, mapped to the authored editor document. */
|
|
69
|
+
const toAuthoredFindMatch = (projection, match) => {
|
|
70
|
+
const toEditorRange = ({ from, to }) => ({
|
|
71
|
+
from: projection.toEditor(from, 1),
|
|
72
|
+
to: projection.toEditor(to, -1)
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
49
75
|
paragraphIndex: match.paragraphIndex,
|
|
50
76
|
startOffset: match.startOffset,
|
|
51
77
|
endOffset: match.endOffset,
|
|
52
78
|
text: match.text,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
79
|
+
...toEditorRange(match),
|
|
80
|
+
...match.excludedRanges && { excludedRanges: match.excludedRanges.map(toEditorRange) },
|
|
81
|
+
...match.atomicTextRanges && { atomicTextRanges: match.atomicTextRanges.map((atom) => ({
|
|
82
|
+
...toEditorRange(atom),
|
|
83
|
+
startOffset: atom.startOffset,
|
|
84
|
+
endOffset: atom.endOffset
|
|
85
|
+
})) }
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
/** Replacement policy for a projected body match, in the shared eligibility vocabulary. */
|
|
89
|
+
const projectedReplacement = (state, viewMatch, authored) => {
|
|
90
|
+
const atom = authored.atomicTextRanges?.at(0);
|
|
91
|
+
if (atom) return {
|
|
92
|
+
status: "blocked",
|
|
93
|
+
reason: state.doc.nodeAt(atom.from)?.type.name === "field" ? "field-result" : "atomic-content"
|
|
94
|
+
};
|
|
95
|
+
return authored.to - authored.from === viewMatch.to - viewMatch.from ? { status: "allowed" } : {
|
|
96
|
+
status: "blocked",
|
|
97
|
+
reason: "hidden-content"
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Search every story a display mode shows. All Markup searches the package
|
|
102
|
+
* stories. A resolved review view searches its body through the projection the
|
|
103
|
+
* layout paints, so body ranges address the authored editor document; anchored
|
|
104
|
+
* shapes, headers, footers, notes and comments keep the package search owner
|
|
105
|
+
* with the same display mode. Returns null while a review view has no body
|
|
106
|
+
* editor state to project.
|
|
107
|
+
*/
|
|
108
|
+
const findInDisplayedDocument = ({ document, state, searchText, options, context }) => {
|
|
109
|
+
const displayMode = options.displayMode ?? "all-markup";
|
|
110
|
+
if (displayMode === "all-markup" || state === void 0) return findInDocument(document, searchText, options, context);
|
|
111
|
+
if (state === null) return null;
|
|
112
|
+
const packageMatches = findInDocument(document, searchText, options, context);
|
|
113
|
+
const projection = projectMarkupView(state, displayMode);
|
|
114
|
+
if (projection.type === "authored" || !searchText) return packageMatches;
|
|
115
|
+
const bodyMatches = findInProseMirrorDocument(projection.doc, searchText, options).map((viewMatch) => {
|
|
116
|
+
const authored = toAuthoredFindMatch(projection, viewMatch);
|
|
117
|
+
const { from, to, excludedRanges, atomicTextRanges } = authored;
|
|
118
|
+
return {
|
|
119
|
+
paragraphIndex: authored.paragraphIndex,
|
|
120
|
+
contentIndex: 0,
|
|
121
|
+
startOffset: authored.startOffset,
|
|
122
|
+
endOffset: authored.endOffset,
|
|
123
|
+
text: authored.text,
|
|
124
|
+
story: "main",
|
|
125
|
+
replacement: projectedReplacement(state, viewMatch, authored),
|
|
126
|
+
authoredRange: {
|
|
127
|
+
from,
|
|
128
|
+
to,
|
|
129
|
+
...excludedRanges && { excludedRanges },
|
|
130
|
+
...atomicTextRanges && { atomicTextRanges }
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
const anchorEnds = [];
|
|
135
|
+
forEachSearchParagraph(state.doc, (paragraph, paragraphPos, paragraphIndex) => {
|
|
136
|
+
anchorEnds[paragraphIndex] = paragraphPos + paragraph.nodeSize;
|
|
137
|
+
return true;
|
|
138
|
+
});
|
|
139
|
+
const bodyShapeMatches = packageMatches.filter((match) => match.story === "main" && match.textBoxIndex !== void 0);
|
|
140
|
+
const orderedBody = [];
|
|
141
|
+
let shapeIndex = 0;
|
|
142
|
+
const shapeAnchorEnd = (match) => match.anchorParagraphIndex !== void 0 && anchorEnds[match.anchorParagraphIndex] || Number.POSITIVE_INFINITY;
|
|
143
|
+
for (const bodyMatch of bodyMatches) {
|
|
144
|
+
const from = bodyMatch.authoredRange?.from ?? 0;
|
|
145
|
+
while (shapeIndex < bodyShapeMatches.length) {
|
|
146
|
+
const shapeMatch = bodyShapeMatches[shapeIndex];
|
|
147
|
+
if (!shapeMatch || shapeAnchorEnd(shapeMatch) > from) break;
|
|
148
|
+
orderedBody.push(shapeMatch);
|
|
149
|
+
shapeIndex++;
|
|
150
|
+
}
|
|
151
|
+
orderedBody.push(bodyMatch);
|
|
152
|
+
}
|
|
153
|
+
orderedBody.push(...bodyShapeMatches.slice(shapeIndex));
|
|
154
|
+
return [...orderedBody, ...packageMatches.filter((match) => match.story !== "main" || match.textBoxIndex === void 0 && match.commentId !== void 0)];
|
|
56
155
|
};
|
|
57
156
|
function forEachSearchParagraph(doc, visit) {
|
|
58
157
|
let paragraphIndex = 0;
|
|
@@ -103,54 +202,56 @@ function resolveTextRangeInParagraph({ paragraph, paragraphPos, startOffset, end
|
|
|
103
202
|
to: null
|
|
104
203
|
};
|
|
105
204
|
const pageBreakOffsets = [];
|
|
205
|
+
const excludedTextRanges = [];
|
|
206
|
+
const excludedRanges = [];
|
|
207
|
+
const atomicTextRanges = [];
|
|
106
208
|
paragraph.descendants((node, pos) => {
|
|
209
|
+
if ((node.type.name === "field" || node.type.name === "structuredField") && isPageDependentSearchField(expectFieldAttrs(node).instruction)) {
|
|
210
|
+
const length = node.type.name === "field" ? expectFieldAttrs(node).displayText.length : getInlineDisplayText(node).length;
|
|
211
|
+
excludedTextRanges.push({
|
|
212
|
+
start: textOffset,
|
|
213
|
+
end: textOffset + length
|
|
214
|
+
});
|
|
215
|
+
}
|
|
107
216
|
if (node.type.name === "pageBreakRun") {
|
|
108
217
|
pageBreakOffsets.push(textOffset);
|
|
109
218
|
return false;
|
|
110
219
|
}
|
|
220
|
+
if (isNoteReferenceText(node)) {
|
|
221
|
+
const from = paragraphPos + 1 + pos;
|
|
222
|
+
excludedRanges.push({
|
|
223
|
+
from,
|
|
224
|
+
to: from + node.nodeSize
|
|
225
|
+
});
|
|
226
|
+
}
|
|
111
227
|
const tokenLength = getSearchTextTokenLength(node);
|
|
112
228
|
if (tokenLength === 0) return true;
|
|
113
229
|
const textStart = textOffset;
|
|
114
230
|
const textEnd = textStart + tokenLength;
|
|
115
231
|
const nodeStart = paragraphPos + 1 + pos;
|
|
116
|
-
|
|
117
|
-
if (
|
|
232
|
+
const atomic = node.type.name === "field" || node.type.name === "preservedXml";
|
|
233
|
+
if (atomic && textStart < endOffset && textEnd > startOffset) atomicTextRanges.push({
|
|
234
|
+
from: nodeStart,
|
|
235
|
+
to: nodeStart + node.nodeSize,
|
|
236
|
+
startOffset: Math.max(0, startOffset - textStart),
|
|
237
|
+
endOffset: Math.min(tokenLength, endOffset - textStart)
|
|
238
|
+
});
|
|
239
|
+
if (range.from === null && startOffset >= textStart && startOffset < textEnd) range.from = atomic ? nodeStart : nodeStart + Math.min(startOffset - textStart, node.nodeSize);
|
|
240
|
+
if (range.to === null && endOffset > textStart && endOffset <= textEnd) range.to = atomic ? nodeStart + node.nodeSize : nodeStart + Math.min(endOffset - textStart, node.nodeSize);
|
|
118
241
|
textOffset = textEnd;
|
|
119
242
|
return range.to === null;
|
|
120
243
|
});
|
|
121
|
-
if (range.from === null || range.to === null || range.from >= range.to || pageBreakOffsets.some((offset) => offset > startOffset && offset < endOffset)) return null;
|
|
244
|
+
if (range.from === null || range.to === null || range.from >= range.to || pageBreakOffsets.some((offset) => offset > startOffset && offset < endOffset) || excludedTextRanges.some(({ start, end }) => start < endOffset && end > startOffset)) return null;
|
|
245
|
+
const from = range.from;
|
|
246
|
+
const to = range.to;
|
|
247
|
+
const visibleExcludedRanges = excludedRanges.filter((anchor) => anchor.from < to && anchor.to > from);
|
|
122
248
|
return {
|
|
123
|
-
from
|
|
124
|
-
to
|
|
249
|
+
from,
|
|
250
|
+
to,
|
|
251
|
+
...atomicTextRanges.length > 0 && { atomicTextRanges },
|
|
252
|
+
...visibleExcludedRanges.length > 0 && { excludedRanges: visibleExcludedRanges }
|
|
125
253
|
};
|
|
126
254
|
}
|
|
127
|
-
|
|
128
|
-
if (node.isText) return node.text?.length ?? 0;
|
|
129
|
-
if (node.type.name === "tab" || node.type.name === "hardBreak" || node.type.name === "symbol") return 1;
|
|
130
|
-
return 0;
|
|
131
|
-
}
|
|
132
|
-
function getSearchableParagraphText(paragraph) {
|
|
133
|
-
let text = "";
|
|
134
|
-
paragraph.descendants((node) => {
|
|
135
|
-
if (node.isText) {
|
|
136
|
-
text += node.text ?? "";
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
if (node.type.name === "tab") {
|
|
140
|
-
text += " ";
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
if (node.type.name === "hardBreak") {
|
|
144
|
-
text += "\n";
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
if (node.type.name === "symbol") {
|
|
148
|
-
text += decodeOoxmlSymbolCharacter(expectSymbolAttrs(node).char) ?? "";
|
|
149
|
-
return false;
|
|
150
|
-
}
|
|
151
|
-
return true;
|
|
152
|
-
});
|
|
153
|
-
return text;
|
|
154
|
-
}
|
|
255
|
+
const getSearchTextTokenLength = (node) => getInlineDisplayToken(node)?.length ?? 0;
|
|
155
256
|
//#endregion
|
|
156
|
-
export { findInMarkupView, findInProseMirrorDocument, resolveFindMatchRange };
|
|
257
|
+
export { findInDisplayedDocument, findInMarkupView, findInProseMirrorDocument, resolveFindMatchRange, resolveFindMatchRanges };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Node } from "prosemirror-model";
|
|
2
|
+
//#region src/prosemirror/inlineDisplayText.d.ts
|
|
3
|
+
/** Native note-reference labels are navigation anchors, outside searchable text. */
|
|
4
|
+
declare const isNoteReferenceText: (node: Node) => boolean;
|
|
5
|
+
/** A leaf's logical text; null means a transparent container to descend into. */
|
|
6
|
+
declare const getInlineDisplayToken: (node: Node) => string | null;
|
|
7
|
+
/** Visible inline text, including cached source atoms and native run tokens. */
|
|
8
|
+
declare const getInlineDisplayText: (paragraph: Node) => string;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { getInlineDisplayText, getInlineDisplayToken, isNoteReferenceText };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { decodeOoxmlSymbolCharacter } from "../utils/ooxmlSymbol.js";
|
|
2
|
+
import { expectFieldAttrs, expectPreservedXmlAttrs, expectSymbolAttrs } from "./attrs/index.js";
|
|
3
|
+
//#region src/prosemirror/inlineDisplayText.ts
|
|
4
|
+
/** Native note-reference labels are navigation anchors, outside searchable text. */
|
|
5
|
+
const isNoteReferenceText = (node) => node.isText && node.marks.some((mark) => mark.type.name === "footnoteRef");
|
|
6
|
+
/** A leaf's logical text; null means a transparent container to descend into. */
|
|
7
|
+
const getInlineDisplayToken = (node) => {
|
|
8
|
+
if (isNoteReferenceText(node)) return "";
|
|
9
|
+
if (node.type.name === "field") return expectFieldAttrs(node).displayText;
|
|
10
|
+
if (node.type.name === "preservedXml") return expectPreservedXmlAttrs(node).text;
|
|
11
|
+
if (node.isText) return node.text ?? "";
|
|
12
|
+
if (node.type.name === "tab") return " ";
|
|
13
|
+
if (node.type.name === "hardBreak") return "\n";
|
|
14
|
+
if (node.type.name === "symbol") return decodeOoxmlSymbolCharacter(expectSymbolAttrs(node).char) ?? "";
|
|
15
|
+
return null;
|
|
16
|
+
};
|
|
17
|
+
/** Visible inline text, including cached source atoms and native run tokens. */
|
|
18
|
+
const getInlineDisplayText = (paragraph) => {
|
|
19
|
+
let text = "";
|
|
20
|
+
paragraph.descendants((node) => {
|
|
21
|
+
const token = getInlineDisplayToken(node);
|
|
22
|
+
if (token === null) return true;
|
|
23
|
+
text += token;
|
|
24
|
+
return false;
|
|
25
|
+
});
|
|
26
|
+
return text;
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
export { getInlineDisplayText, getInlineDisplayToken, isNoteReferenceText };
|
|
@@ -21,7 +21,7 @@ declare const TRACKED_RUN_INLINE_ATOM_DISPOSITIONS: Readonly<{
|
|
|
21
21
|
readonly pageBreakRun: "page-break-carrier";
|
|
22
22
|
readonly preservedXml: "carry";
|
|
23
23
|
readonly rangeAnchor: "transparent";
|
|
24
|
-
readonly renderedPageBreak: "
|
|
24
|
+
readonly renderedPageBreak: "carry";
|
|
25
25
|
readonly shape: "carry";
|
|
26
26
|
readonly structuredField: "carry";
|
|
27
27
|
readonly symbol: "carry";
|
|
@@ -20,7 +20,7 @@ const TRACKED_RUN_INLINE_ATOM_DISPOSITIONS = Object.freeze({
|
|
|
20
20
|
pageBreakRun: "page-break-carrier",
|
|
21
21
|
preservedXml: "carry",
|
|
22
22
|
rangeAnchor: "transparent",
|
|
23
|
-
renderedPageBreak: "
|
|
23
|
+
renderedPageBreak: "carry",
|
|
24
24
|
shape: "carry",
|
|
25
25
|
structuredField: "carry",
|
|
26
26
|
symbol: "carry",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { Layout } from "../layout-engine/types.js";
|
|
3
|
+
import { FindMatch } from "./findReplace.js";
|
|
4
|
+
import { FindMatchRange } from "../prosemirror/findReplaceSelection.js";
|
|
5
|
+
import { Node } from "prosemirror-model";
|
|
6
|
+
import { OpStory } from "@stll/docx-core/ops";
|
|
7
|
+
//#region src/utils/findMatchView.d.ts
|
|
8
|
+
/** The same page variant selection used by the painter, including unmounted pages. */
|
|
9
|
+
declare const getRenderedSearchStories: (layout: Layout | null) => OpStory[];
|
|
10
|
+
type ResolvedMatch = FindMatchRange & {
|
|
11
|
+
index: number;
|
|
12
|
+
story: OpStory;
|
|
13
|
+
};
|
|
14
|
+
type FindMatchViewOptions = {
|
|
15
|
+
container: HTMLElement;
|
|
16
|
+
document: document_d_exports.Document;
|
|
17
|
+
bodyDoc?: Node | undefined;
|
|
18
|
+
matches: readonly FindMatch[];
|
|
19
|
+
commentRoot?: HTMLElement | undefined;
|
|
20
|
+
layout?: Layout | null | undefined;
|
|
21
|
+
};
|
|
22
|
+
/** Resolve each story once; box positions are local to their parent story. */
|
|
23
|
+
declare const resolveDocumentFindRanges: ({ document, bodyDoc, matches }: Omit<FindMatchViewOptions, "container" | "commentRoot" | "layout">) => ResolvedMatch[];
|
|
24
|
+
/** Paint search geometry over the existing page DOM, without changing editor state. */
|
|
25
|
+
declare const createFindMatchView: (options: FindMatchViewOptions) => {
|
|
26
|
+
paint: (index: number) => void;
|
|
27
|
+
reveal: (index: number) => boolean;
|
|
28
|
+
navigate: (index: number, activateComment?: (commentId: number) => void) => void;
|
|
29
|
+
destroy: () => void;
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { createFindMatchView, getRenderedSearchStories, resolveDocumentFindRanges };
|