/
formatSegmentWithContentModel.ts
91 lines (82 loc) · 3.49 KB
/
formatSegmentWithContentModel.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { adjustWordSelection } from '../../modelApi/selection/adjustWordSelection';
import { getSelectedSegmentsAndParagraphs } from 'roosterjs-content-model-dom';
import type {
ContentModelDocument,
ContentModelParagraph,
ContentModelSegment,
ContentModelSegmentFormat,
IEditor,
} from 'roosterjs-content-model-types';
/**
* Invoke a callback to format the selected segment using Content Model
* @param editor The editor object
* @param apiName Name of API this calling this function. This is mostly for logging.
* @param toggleStyleCallback The callback to format the segment. It will be called with current selected table. If no table is selected, it will not be called.
* @param segmentHasStyleCallback The callback used for checking if the given segment already has required format
* @param includingFormatHolder True to also include format holder of list item when search selected segments
* @param afterFormatCallback A callback to invoke after format is applied to all selected segments and before the change is applied to DOM tree
*/
export function formatSegmentWithContentModel(
editor: IEditor,
apiName: string,
toggleStyleCallback: (
format: ContentModelSegmentFormat,
isTuringOn: boolean,
segment: ContentModelSegment | null,
paragraph: ContentModelParagraph | null
) => void,
segmentHasStyleCallback?: (
format: ContentModelSegmentFormat,
segment: ContentModelSegment | null,
paragraph: ContentModelParagraph | null
) => boolean,
includingFormatHolder?: boolean,
afterFormatCallback?: (model: ContentModelDocument) => void
) {
editor.formatContentModel(
(model, context) => {
let segmentAndParagraphs = getSelectedSegmentsAndParagraphs(
model,
!!includingFormatHolder
);
let isCollapsedSelection =
segmentAndParagraphs.length == 1 &&
segmentAndParagraphs[0][0].segmentType == 'SelectionMarker';
if (isCollapsedSelection) {
const para = segmentAndParagraphs[0][1];
const path = segmentAndParagraphs[0][2];
segmentAndParagraphs = adjustWordSelection(
model,
segmentAndParagraphs[0][0]
).map(x => [x, para, path]);
if (segmentAndParagraphs.length > 1) {
isCollapsedSelection = false;
}
}
const formatsAndSegments: [
ContentModelSegmentFormat,
ContentModelSegment | null,
ContentModelParagraph | null
][] = segmentAndParagraphs.map(item => [item[0].format, item[0], item[1]]);
const isTurningOff = segmentHasStyleCallback
? formatsAndSegments.every(([format, segment, paragraph]) =>
segmentHasStyleCallback(format, segment, paragraph)
)
: false;
formatsAndSegments.forEach(([format, segment, paragraph]) =>
toggleStyleCallback(format, !isTurningOff, segment, paragraph)
);
afterFormatCallback?.(model);
if (isCollapsedSelection) {
context.newPendingFormat = segmentAndParagraphs[0][0].format;
editor.focus();
return false;
} else {
return formatsAndSegments.length > 0;
}
},
{
apiName,
}
);
}