Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content Model cache improvement: Let Content model update cache for child list change #2613

Merged
merged 133 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
c30c84a
KeyboardEnter
JiuqingSong Apr 29, 2024
9865552
fix comment
JiuqingSong Apr 30, 2024
a8af367
fix test
JiuqingSong Apr 30, 2024
ac1a2c1
improve
JiuqingSong May 1, 2024
18ac906
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 1, 2024
bc99d9d
Let Content Model cache handle child list change
JiuqingSong May 2, 2024
fc1d4ea
pushMerge branch 'u/jisong/keyboardenter' into u/jisong/reconcilechi…
JiuqingSong May 2, 2024
817530f
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 2, 2024
0b3b22b
Merge branch 'master' into u/jisong/reconcilechildlist
JiuqingSong May 2, 2024
bccb2ed
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 6, 2024
8304dc9
Scroll caret into view when call formatContentModel
JiuqingSong May 6, 2024
6506a6e
Merge branch 'u/jisong/scrollintoview' into u/jisong/keyboardenter
JiuqingSong May 6, 2024
65913c0
scroll caret into view
JiuqingSong May 6, 2024
844e1f7
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 6, 2024
7468a88
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 7, 2024
34f7b06
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 10, 2024
7cc5a1b
Readonly types (3rd try
JiuqingSong May 13, 2024
3ff0779
Improve
JiuqingSong May 14, 2024
950a4ae
fix build
JiuqingSong May 14, 2024
2574fe2
Improve
JiuqingSong May 14, 2024
0180d29
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 14, 2024
47b21f3
improve
JiuqingSong May 14, 2024
bd6b0cb
Improve
JiuqingSong May 14, 2024
cf3ea78
Add shallow mutable type
JiuqingSong May 14, 2024
e14e506
improve
JiuqingSong May 14, 2024
9a2d449
Improve
JiuqingSong May 14, 2024
719f5ed
improve
JiuqingSong May 14, 2024
caf7ef1
improve
JiuqingSong May 15, 2024
29495db
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 16, 2024
0230a26
add test
JiuqingSong May 16, 2024
46fbe45
Readonly types step 2
JiuqingSong May 16, 2024
5f9b88b
Readonly types step 3
JiuqingSong May 16, 2024
4fa3138
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 16, 2024
ce2e31a
Readonly type step 4
JiuqingSong May 16, 2024
2afcf38
add test
JiuqingSong May 16, 2024
b2a3f6c
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 16, 2024
adb26a0
Improve
JiuqingSong May 16, 2024
b77e4b0
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 16, 2024
85b50f2
improve
JiuqingSong May 17, 2024
e91e1a8
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 17, 2024
6dbd78b
improve
JiuqingSong May 17, 2024
d0ee665
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 17, 2024
6d7d041
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 17, 2024
6c35a70
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 17, 2024
1e157b1
Merge branch 'u/jisong/readonlytypes_step_3' into u/jisong/readonlyty…
JiuqingSong May 17, 2024
c92c7db
Readonly types step 5: dom package
JiuqingSong May 17, 2024
719c917
add change
JiuqingSong May 17, 2024
3ec1ec0
Merge branch 'master' into u/jisong/readonlytypes_step_5
JiuqingSong May 18, 2024
f659ca9
Merge branch 'master' into u/jisong/readonlytypes_step_2
JiuqingSong May 19, 2024
acceb1d
improve
JiuqingSong May 19, 2024
d5b159d
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 19, 2024
93b0247
Merge branch 'u/jisong/readonlytypes_step_4' into u/jisong/readonlyty…
JiuqingSong May 19, 2024
f7384a4
Readonly types step 6
JiuqingSong May 20, 2024
7bd493a
fix build
JiuqingSong May 20, 2024
a69738f
Merge branch 'master' into u/jisong/readonlytype0513
JiuqingSong May 20, 2024
b4ab134
improve
JiuqingSong May 20, 2024
dea9f7f
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 20, 2024
6d9fe1e
Merge branch 'u/jisong/readonlytype0513' into u/jisong/readonlytypes_…
JiuqingSong May 20, 2024
124559c
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
df68a71
Merge branch 'u/jisong/readonlytypes_step_3' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
9301264
Merge branch 'u/jisong/readonlytypes_step_4' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
289e3f9
Merge branch 'u/jisong/readonlytypes_step_5' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
f745036
Merge branch 'master' into u/jisong/readonlytypes_step_2
JiuqingSong May 20, 2024
806a1d3
Improve
JiuqingSong May 20, 2024
fa84daa
Merge branch 'master' into u/jisong/readonlytypes_step_3
JiuqingSong May 20, 2024
de8ca0d
improve
JiuqingSong May 20, 2024
149b315
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
1de55bb
Merge branch 'u/jisong/readonlytypes_step_3' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
588864e
Merge branch 'u/jisong/readonlytypes_step_4' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
7a6b43f
fix test
JiuqingSong May 20, 2024
bd9661d
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
cc17fdb
Merge branch 'u/jisong/readonlytypes_step_4' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
62e491f
Improve
JiuqingSong May 20, 2024
1a43582
Merge branch 'u/jisong/readonlytypes_step_5' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
5f3027f
Improve
JiuqingSong May 20, 2024
829e6ca
fix build
JiuqingSong May 20, 2024
2bc734b
improve
JiuqingSong May 20, 2024
5e72761
improve
JiuqingSong May 20, 2024
3f36928
Merge branch 'u/jisong/readonlytypes_step_2' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
a8cc329
Merge branch 'u/jisong/readonlytypes_step_4' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
fffd11c
Merge branch 'u/jisong/readonlytypes_step_5' into u/jisong/readonlyty…
JiuqingSong May 20, 2024
71f3ba8
Readonly types step 7: Port all other files
JiuqingSong May 20, 2024
5062a70
improve
JiuqingSong May 20, 2024
4bc4412
Readonly type steps 8: Finally enable readonly type
JiuqingSong May 20, 2024
c717e24
fix test
JiuqingSong May 20, 2024
732d153
improve
JiuqingSong May 21, 2024
cd6fe10
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 23, 2024
fe31c04
Merge branch 'master' into u/jisong/readonlytypes_step_6
JiuqingSong May 24, 2024
37b5abe
improve
JiuqingSong May 24, 2024
fedf510
Merge branch 'master' into u/jisong/readonlytypes_step_6
JiuqingSong May 24, 2024
8d6ace8
Merge branch 'u/jisong/readonlytypes_step_6' into u/jisong/readonlyty…
JiuqingSong May 24, 2024
edf9445
Merge branch 'master' into u/jisong/readonlytypes_step_6
JiuqingSong May 28, 2024
bdd5f1b
Merge branch 'u/jisong/readonlytypes_step_6' into u/jisong/readonlyty…
JiuqingSong May 28, 2024
9ac9e08
Merge branch 'u/jisong/readonlytypes_step_7' into u/jisong/readonlyty…
JiuqingSong May 28, 2024
96a4a48
fix build
JiuqingSong May 28, 2024
87ab530
fix build
JiuqingSong May 28, 2024
2edbc0a
fix build
JiuqingSong May 28, 2024
e269e91
Merge branch 'master' into u/jisong/readonlytypes_step_7
JiuqingSong May 29, 2024
c3b766d
Merge branch 'u/jisong/readonlytypes_step_7' into u/jisong/readonlyty…
JiuqingSong May 29, 2024
66db4cd
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 29, 2024
115bf03
Merge branch 'u/jisong/keyboardenter' into u/jisong/reconcilechildlist
JiuqingSong May 29, 2024
a5ef968
Fix build
JiuqingSong May 29, 2024
840cb8d
Merge branch 'u/jisong/keyboardenter' into u/jisong/reconcilechildlist
JiuqingSong May 29, 2024
dd1171c
fix build
JiuqingSong May 29, 2024
472436e
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 29, 2024
09938f2
 'master' into u/jisong/keyboardenter
JiuqingSong May 30, 2024
ad9feeb
improve
JiuqingSong May 30, 2024
3a7d92e
fix build
JiuqingSong May 31, 2024
2bc4b5a
Merge branch 'master' into u/jisong/readonlytypes_step_8
JiuqingSong May 31, 2024
6ae3bb0
Add experimental features
JiuqingSong May 31, 2024
21a0bb0
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong May 31, 2024
c0a41f8
Merge branch 'u/jisong/keyboardenter' into u/jisong/reconcilechildlist
JiuqingSong May 31, 2024
becf627
Merge branch 'u/jisong/readonlytypes_step_8' into u/jisong/reconcilec…
JiuqingSong May 31, 2024
fa4c2ff
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong Jun 3, 2024
0698c39
Improve
JiuqingSong Jun 3, 2024
f1dfe80
fix test
JiuqingSong Jun 3, 2024
37f6b4b
add test
JiuqingSong Jun 3, 2024
1f90c24
add test
JiuqingSong Jun 4, 2024
5491860
Merge branch 'u/jisong/keyboardenter' into u/jisong/reconcilechildlist
JiuqingSong Jun 5, 2024
82d4ce3
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong Jun 5, 2024
aaa58f6
improve
JiuqingSong Jun 5, 2024
280345f
do not scroll caret into view for now
JiuqingSong Jun 5, 2024
ff29216
Merge branch 'master' into u/jisong/keyboardenter
JiuqingSong Jun 5, 2024
8be7099
Merge branch 'u/jisong/keyboardenter' into u/jisong/reconcilechildlist
JiuqingSong Jun 5, 2024
6077ae6
Merge branch 'master' into u/jisong/reconcilechildlist
JiuqingSong Jun 6, 2024
a8e46cd
improve
JiuqingSong Jun 6, 2024
ac47a4d
fix test
JiuqingSong Jun 6, 2024
9443a20
Merge branch 'master' into u/jisong/reconcilechildlist
JiuqingSong Jun 7, 2024
30455ff
Improve
JiuqingSong Jun 10, 2024
b296c39
fix test
JiuqingSong Jun 10, 2024
c46cd18
add test cases
JiuqingSong Jun 10, 2024
476be2a
Merge branch 'master' into u/jisong/reconcilechildlist
JiuqingSong Jun 12, 2024
e17d5a5
Merge branch 'master' into u/jisong/reconcilechildlist
JiuqingSong Jun 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export function formatSegmentWithContentModel(
true /*mutate*/
);
let isCollapsedSelection =
segmentAndParagraphs.length == 1 &&
segmentAndParagraphs[0][0].segmentType == 'SelectionMarker';
segmentAndParagraphs.length >= 1 &&
segmentAndParagraphs.every(x => x[0].segmentType == 'SelectionMarker');

if (isCollapsedSelection) {
const para = segmentAndParagraphs[0][1];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createDomToModelContextForSanitizing } from '../createModelFromHtml/createDomToModelContextForSanitizing';
import {
ChangeSource,
EmptySegmentFormat,
cloneModel,
domToContentModel,
getSegmentTextFormat,
Expand All @@ -12,26 +13,11 @@ import type {
ClipboardData,
CloneModelOptions,
ContentModelDocument,
ContentModelSegmentFormat,
IEditor,
MergeModelOption,
ReadonlyContentModelDocument,
} from 'roosterjs-content-model-types';

const EmptySegmentFormat: Required<ContentModelSegmentFormat> = {
backgroundColor: '',
fontFamily: '',
fontSize: '',
fontWeight: '',
italic: false,
letterSpacing: '',
lineHeight: '',
strikethrough: false,
superOrSubScriptSequence: '',
textColor: '',
underline: false,
};

const CloneOption: CloneModelOptions = {
includeCachedElement: (node, type) => (type == 'cache' ? undefined : node),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ export const setContentModel: SetContentModel = (core, model, option, onNodeCrea
}

// Clear pending mutations since we will use our latest model object to replace existing cache
core.cache.textMutationObserver?.flushMutations();
core.cache.cachedModel = model;
core.cache.textMutationObserver?.flushMutations(model);
}

return selection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
PluginEvent,
PluginWithState,
EditorOptions,
ContentModelDocument,
} from 'roosterjs-content-model-types';

/**
Expand All @@ -23,15 +24,24 @@ class CachePlugin implements PluginWithState<CachePluginState> {
* @param contentDiv The editor content DIV
*/
constructor(option: EditorOptions, contentDiv: HTMLDivElement) {
this.state = option.disableCache
? {}
: {
domIndexer: new DomIndexerImpl(
option.experimentalFeatures &&
option.experimentalFeatures.indexOf('PersistCache') >= 0
),
textMutationObserver: createTextMutationObserver(contentDiv, this.onMutation),
};
if (option.disableCache) {
this.state = {};
} else {
const domIndexer = new DomIndexerImpl(
option.experimentalFeatures &&
option.experimentalFeatures.indexOf('PersistCache') >= 0
);

this.state = {
domIndexer: domIndexer,
textMutationObserver: createTextMutationObserver(
contentDiv,
domIndexer,
this.onMutation,
this.onSkipMutation
),
};
}
}

/**
Expand Down Expand Up @@ -125,6 +135,13 @@ class CachePlugin implements PluginWithState<CachePluginState> {
}
};

private onSkipMutation = (newModel: ContentModelDocument) => {
if (!this.editor?.isInShadowEdit()) {
this.state.cachedModel = newModel;
this.state.cachedSelection = undefined;
}
};

private onNativeSelectionChange = () => {
if (this.editor?.hasFocus()) {
this.updateCachedModel(this.editor);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {
EmptySegmentFormat,
createSelectionMarker,
createText,
getObjectKeys,
isNodeOfType,
setSelection,
} from 'roosterjs-content-model-dom';
Expand All @@ -9,6 +11,7 @@ import type {
ContentModelDocument,
ContentModelParagraph,
ContentModelSegment,
ContentModelSegmentFormat,
ContentModelSelectionMarker,
ContentModelTable,
ContentModelTableRow,
Expand All @@ -19,23 +22,65 @@ import type {
Selectable,
} from 'roosterjs-content-model-types';

interface SegmentItem {
/**
* @internal Export for test only
*/
export interface SegmentItem {
paragraph: ContentModelParagraph;
segments: ContentModelSegment[];
}

interface TableItem {
/**
* @internal Export for test only
*/
export interface TableItem {
tableRows: ContentModelTableRow[];
}

interface IndexedSegmentNode extends Node {
/**
* @internal Export for test only
*/
export interface IndexedSegmentNode extends Node {
__roosterjsContentModel: SegmentItem;
}

interface IndexedTableElement extends HTMLTableElement {
/**
* @internal Export for test only
*/
export interface IndexedTableElement extends HTMLTableElement {
__roosterjsContentModel: TableItem;
}

/**
* Context object used by DomIndexer when reconcile mutations with child list
*/
interface ReconcileChildListContext {
/**
* Index of segment in current paragraph
*/
segIndex: number;

/**
* The current paragraph that we are handling
*/
paragraph?: ContentModelParagraph;

/**
* Text node that is added from mutation but has not been handled. This can happen when we first see an added node then later we see a removed one.
* e.g. Type text in an empty paragraph (&lt;div&gt;&lt;br&gt;&lt;/div&gt;), so a text node will be added and &lt;BR&gt; will be removed.
* Set to a valid text node means we need to handle it later. If it is finally not handled, that means we need to clear cache
* Set to undefined (initial value) means no pending text node is hit yet (valid case)
* Set to null means there was a pending text node which is already handled, so if we see another pending text node,
* we should clear cache since we don't know how to handle it
*/
pendingTextNode?: Text | null;

/**
* Format of the removed segment, this will be used as the format for newly created segment
*/
format?: ContentModelSegmentFormat;
}

function isIndexedSegment(node: Node): node is IndexedSegmentNode {
const { paragraph, segments } = (node as IndexedSegmentNode).__roosterjsContentModel ?? {};

Expand All @@ -47,12 +92,16 @@ function isIndexedSegment(node: Node): node is IndexedSegmentNode {
);
}

function getIndexedSegmentItem(node: Node | null): SegmentItem | null {
return node && isIndexedSegment(node) ? node.__roosterjsContentModel : null;
}

/**
* @internal
* Implementation of DomIndexer
*/
export class DomIndexerImpl implements DomIndexer {
constructor(public readonly persistCache?: boolean) {}
constructor(private readonly persistCache?: boolean) {}

onSegment(segmentNode: Node, paragraph: ContentModelParagraph, segment: ContentModelSegment[]) {
const indexedText = segmentNode as IndexedSegmentNode;
Expand All @@ -70,9 +119,7 @@ export class DomIndexerImpl implements DomIndexer {
if (!previousText) {
previousText = child;
} else {
const item = isIndexedSegment(previousText)
? previousText.__roosterjsContentModel
: undefined;
const item = getIndexedSegmentItem(previousText);

if (item && isIndexedSegment(child)) {
item.segments = item.segments.concat(
Expand Down Expand Up @@ -171,6 +218,37 @@ export class DomIndexerImpl implements DomIndexer {
return false;
}

reconcileChildList(addedNodes: ArrayLike<Node>, removedNodes: ArrayLike<Node>): boolean {
if (!this.persistCache) {
return false;
}

let canHandle = true;
const context: ReconcileChildListContext = {
segIndex: -1,
};

// First process added nodes
const addedNode = addedNodes[0];

if (addedNodes.length == 1 && isNodeOfType(addedNode, 'TEXT_NODE')) {
canHandle = this.reconcileAddedNode(addedNode, context);
} else if (addedNodes.length > 0) {
canHandle = false;
}

// Second, process removed nodes
const removedNode = removedNodes[0];

if (canHandle && removedNodes.length == 1) {
canHandle = this.reconcileRemovedNode(removedNode, context);
} else if (removedNodes.length > 0) {
canHandle = false;
}

return canHandle && !context.pendingTextNode;
}

private isCollapsed(selection: RangeSelectionForCache): boolean {
const { start, end } = selection;

Expand All @@ -189,9 +267,10 @@ export class DomIndexerImpl implements DomIndexer {

private insertMarker(node: Node | null, isAfter: boolean): Selectable | undefined {
let marker: ContentModelSelectionMarker | undefined;
const segmentItem = node && getIndexedSegmentItem(node);

if (node && isIndexedSegment(node)) {
const { paragraph, segments } = node.__roosterjsContentModel;
if (segmentItem) {
const { paragraph, segments } = segmentItem;
const index = paragraph.segments.indexOf(segments[0]);

if (index >= 0) {
Expand Down Expand Up @@ -294,4 +373,110 @@ export class DomIndexerImpl implements DomIndexer {

return selectable;
}

private reconcileAddedNode(node: Text, context: ReconcileChildListContext): boolean {
let segmentItem: SegmentItem | null = null;
let index = -1;
let existingSegment: ContentModelSegment;
const { previousSibling, nextSibling } = node;

if (
(segmentItem = getIndexedSegmentItem(previousSibling)) &&
(existingSegment = segmentItem.segments[segmentItem.segments.length - 1]) &&
(index = segmentItem.paragraph.segments.indexOf(existingSegment)) >= 0
) {
// When we can find indexed segment before current one, use it as the insert index
this.indexNode(segmentItem.paragraph, index + 1, node, existingSegment.format);
} else if (
(segmentItem = getIndexedSegmentItem(nextSibling)) &&
(existingSegment = segmentItem.segments[0]) &&
(index = segmentItem.paragraph.segments.indexOf(existingSegment)) >= 0
) {
// When we can find indexed segment after current one, use it as the insert index
this.indexNode(segmentItem.paragraph, index, node, existingSegment.format);
} else if (context.paragraph && context.segIndex >= 0) {
// When there is indexed paragraph from removed nodes, we can use it as the insert index
this.indexNode(context.paragraph, context.segIndex, node, context.format);
} else if (context.pendingTextNode === undefined) {
// When we can't find the insert index, set current node as pending node
// so later we can pick it up when we have enough info when processing removed node
// Only do this when pendingTextNode is undefined. If it is null it means there was already a pending node before
// and in that case we should return false since we can't handle two pending text node
context.pendingTextNode = node;
} else {
return false;
}

return true;
}

private reconcileRemovedNode(node: Node, context: ReconcileChildListContext): boolean {
let segmentItem: SegmentItem | null = null;
let removingSegment: ContentModelSegment;

if (
context.segIndex < 0 &&
!context.paragraph && // No previous removed segment or related paragraph found, and
(segmentItem = getIndexedSegmentItem(node)) && // The removed node is indexed, and
(removingSegment = segmentItem.segments[0]) // There is at least one related segment
) {
// Now we can remove the indexed segment from the paragraph, and remember it, later we may need to use it
context.format = removingSegment.format;
context.paragraph = segmentItem.paragraph;
context.segIndex = segmentItem.paragraph.segments.indexOf(segmentItem.segments[0]);

if (context.segIndex < 0) {
// Indexed segment is not under paragraph, something wrong happens, we cannot keep handling
return false;
}

for (let i = 0; i < segmentItem.segments.length; i++) {
const index = segmentItem.paragraph.segments.indexOf(segmentItem.segments[i]);

if (index >= 0) {
segmentItem.paragraph.segments.splice(index, 1);
}
}

if (context.pendingTextNode) {
// If we have pending text node added but not indexed, do it now
this.indexNode(
context.paragraph,
context.segIndex,
context.pendingTextNode,
segmentItem.segments[0].format
);

// Set to null since we have processed it.
// Next time we see a pending node we know we have already processed one so it is a situation we cannot handle
context.pendingTextNode = null;
}

return true;
} else {
return false;
}
}

private indexNode(
paragraph: ContentModelParagraph,
index: number,
textNode: Text,
format?: ContentModelSegmentFormat
) {
const copiedFormat = format ? { ...format } : undefined;

if (copiedFormat) {
getObjectKeys(copiedFormat).forEach(key => {
if (EmptySegmentFormat[key] === undefined) {
delete copiedFormat[key];
}
});
}

const text = createText(textNode.textContent ?? '', copiedFormat);

paragraph.segments.splice(index, 0, text);
this.onSegment(textNode, paragraph, [text]);
}
}
Loading
Loading