@itwin/core-backend 5.2.0-dev.7 → 5.3.0-dev.1
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/CHANGELOG.md +36 -1
- package/lib/cjs/BackendHubAccess.d.ts +2 -0
- package/lib/cjs/BackendHubAccess.d.ts.map +1 -1
- package/lib/cjs/BackendHubAccess.js.map +1 -1
- package/lib/cjs/BackendLoggerCategory.d.ts +6 -0
- package/lib/cjs/BackendLoggerCategory.d.ts.map +1 -1
- package/lib/cjs/BackendLoggerCategory.js +6 -0
- package/lib/cjs/BackendLoggerCategory.js.map +1 -1
- package/lib/cjs/BriefcaseManager.d.ts +57 -3
- package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
- package/lib/cjs/BriefcaseManager.js +151 -42
- package/lib/cjs/BriefcaseManager.js.map +1 -1
- package/lib/cjs/CloudSqlite.d.ts +4 -0
- package/lib/cjs/CloudSqlite.d.ts.map +1 -1
- package/lib/cjs/CloudSqlite.js.map +1 -1
- package/lib/cjs/ECDb.d.ts +8 -0
- package/lib/cjs/ECDb.d.ts.map +1 -1
- package/lib/cjs/ECDb.js +22 -0
- package/lib/cjs/ECDb.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +54 -3
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +87 -9
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/IModelHost.d.ts +11 -1
- package/lib/cjs/IModelHost.d.ts.map +1 -1
- package/lib/cjs/IModelHost.js +5 -0
- package/lib/cjs/IModelHost.js.map +1 -1
- package/lib/cjs/IModelIncrementalSchemaLocater.d.ts +1 -5
- package/lib/cjs/IModelIncrementalSchemaLocater.d.ts.map +1 -1
- package/lib/cjs/IModelIncrementalSchemaLocater.js +0 -6
- package/lib/cjs/IModelIncrementalSchemaLocater.js.map +1 -1
- package/lib/cjs/SqliteChangesetReader.d.ts +8 -0
- package/lib/cjs/SqliteChangesetReader.d.ts.map +1 -1
- package/lib/cjs/SqliteChangesetReader.js +11 -0
- package/lib/cjs/SqliteChangesetReader.js.map +1 -1
- package/lib/cjs/StashManager.d.ts +175 -0
- package/lib/cjs/StashManager.d.ts.map +1 -0
- package/lib/cjs/StashManager.js +306 -0
- package/lib/cjs/StashManager.js.map +1 -0
- package/lib/cjs/TxnManager.d.ts +226 -15
- package/lib/cjs/TxnManager.d.ts.map +1 -1
- package/lib/cjs/TxnManager.js +249 -23
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.js +15 -6
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.js.map +1 -1
- package/lib/cjs/annotations/LeaderGeometry.d.ts +3 -2
- package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/LeaderGeometry.js +5 -4
- package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.d.ts +52 -24
- package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.js +49 -59
- package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
- package/lib/cjs/annotations/TextAnnotationGeometry.d.ts +2 -0
- package/lib/cjs/annotations/TextAnnotationGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/TextAnnotationGeometry.js +26 -19
- package/lib/cjs/annotations/TextAnnotationGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextBlockGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/TextBlockGeometry.js +8 -0
- package/lib/cjs/annotations/TextBlockGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextBlockLayout.d.ts +49 -36
- package/lib/cjs/annotations/TextBlockLayout.d.ts.map +1 -1
- package/lib/cjs/annotations/TextBlockLayout.js +204 -135
- package/lib/cjs/annotations/TextBlockLayout.js.map +1 -1
- package/lib/cjs/internal/ChannelAdmin.js +1 -1
- package/lib/cjs/internal/ChannelAdmin.js.map +1 -1
- package/lib/cjs/internal/Symbols.d.ts +1 -0
- package/lib/cjs/internal/Symbols.d.ts.map +1 -1
- package/lib/cjs/internal/Symbols.js +2 -1
- package/lib/cjs/internal/Symbols.js.map +1 -1
- package/lib/cjs/internal/annotations/fields.d.ts +2 -12
- package/lib/cjs/internal/annotations/fields.d.ts.map +1 -1
- package/lib/cjs/internal/annotations/fields.js +49 -45
- package/lib/cjs/internal/annotations/fields.js.map +1 -1
- package/lib/cjs/workspace/Workspace.d.ts +1 -1
- package/lib/cjs/workspace/Workspace.js.map +1 -1
- package/lib/esm/BackendHubAccess.d.ts +2 -0
- package/lib/esm/BackendHubAccess.d.ts.map +1 -1
- package/lib/esm/BackendHubAccess.js.map +1 -1
- package/lib/esm/BackendLoggerCategory.d.ts +6 -0
- package/lib/esm/BackendLoggerCategory.d.ts.map +1 -1
- package/lib/esm/BackendLoggerCategory.js +6 -0
- package/lib/esm/BackendLoggerCategory.js.map +1 -1
- package/lib/esm/BriefcaseManager.d.ts +57 -3
- package/lib/esm/BriefcaseManager.d.ts.map +1 -1
- package/lib/esm/BriefcaseManager.js +152 -43
- package/lib/esm/BriefcaseManager.js.map +1 -1
- package/lib/esm/CloudSqlite.d.ts +4 -0
- package/lib/esm/CloudSqlite.d.ts.map +1 -1
- package/lib/esm/CloudSqlite.js.map +1 -1
- package/lib/esm/ECDb.d.ts +8 -0
- package/lib/esm/ECDb.d.ts.map +1 -1
- package/lib/esm/ECDb.js +22 -0
- package/lib/esm/ECDb.js.map +1 -1
- package/lib/esm/IModelDb.d.ts +54 -3
- package/lib/esm/IModelDb.d.ts.map +1 -1
- package/lib/esm/IModelDb.js +88 -10
- package/lib/esm/IModelDb.js.map +1 -1
- package/lib/esm/IModelHost.d.ts +11 -1
- package/lib/esm/IModelHost.d.ts.map +1 -1
- package/lib/esm/IModelHost.js +5 -0
- package/lib/esm/IModelHost.js.map +1 -1
- package/lib/esm/IModelIncrementalSchemaLocater.d.ts +1 -5
- package/lib/esm/IModelIncrementalSchemaLocater.d.ts.map +1 -1
- package/lib/esm/IModelIncrementalSchemaLocater.js +0 -6
- package/lib/esm/IModelIncrementalSchemaLocater.js.map +1 -1
- package/lib/esm/SqliteChangesetReader.d.ts +8 -0
- package/lib/esm/SqliteChangesetReader.d.ts.map +1 -1
- package/lib/esm/SqliteChangesetReader.js +11 -0
- package/lib/esm/SqliteChangesetReader.js.map +1 -1
- package/lib/esm/StashManager.d.ts +175 -0
- package/lib/esm/StashManager.d.ts.map +1 -0
- package/lib/esm/StashManager.js +301 -0
- package/lib/esm/StashManager.js.map +1 -0
- package/lib/esm/TxnManager.d.ts +226 -15
- package/lib/esm/TxnManager.d.ts.map +1 -1
- package/lib/esm/TxnManager.js +247 -21
- package/lib/esm/TxnManager.js.map +1 -1
- package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
- package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
- package/lib/esm/annotations/ElementDrivesTextAnnotation.js +13 -5
- package/lib/esm/annotations/ElementDrivesTextAnnotation.js.map +1 -1
- package/lib/esm/annotations/LeaderGeometry.d.ts +3 -2
- package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/LeaderGeometry.js +5 -4
- package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
- package/lib/esm/annotations/TextAnnotationElement.d.ts +52 -24
- package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
- package/lib/esm/annotations/TextAnnotationElement.js +51 -61
- package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
- package/lib/esm/annotations/TextAnnotationGeometry.d.ts +2 -0
- package/lib/esm/annotations/TextAnnotationGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/TextAnnotationGeometry.js +26 -19
- package/lib/esm/annotations/TextAnnotationGeometry.js.map +1 -1
- package/lib/esm/annotations/TextBlockGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/TextBlockGeometry.js +8 -0
- package/lib/esm/annotations/TextBlockGeometry.js.map +1 -1
- package/lib/esm/annotations/TextBlockLayout.d.ts +49 -36
- package/lib/esm/annotations/TextBlockLayout.d.ts.map +1 -1
- package/lib/esm/annotations/TextBlockLayout.js +205 -136
- package/lib/esm/annotations/TextBlockLayout.js.map +1 -1
- package/lib/esm/internal/ChannelAdmin.js +1 -1
- package/lib/esm/internal/ChannelAdmin.js.map +1 -1
- package/lib/esm/internal/Symbols.d.ts +1 -0
- package/lib/esm/internal/Symbols.d.ts.map +1 -1
- package/lib/esm/internal/Symbols.js +1 -0
- package/lib/esm/internal/Symbols.js.map +1 -1
- package/lib/esm/internal/annotations/fields.d.ts +2 -12
- package/lib/esm/internal/annotations/fields.d.ts.map +1 -1
- package/lib/esm/internal/annotations/fields.js +51 -47
- package/lib/esm/internal/annotations/fields.js.map +1 -1
- package/lib/esm/test/AnnotationTestUtils.d.ts +5 -1
- package/lib/esm/test/AnnotationTestUtils.d.ts.map +1 -1
- package/lib/esm/test/AnnotationTestUtils.js +6 -1
- package/lib/esm/test/AnnotationTestUtils.js.map +1 -1
- package/lib/esm/test/annotations/Fields.test.js +163 -46
- package/lib/esm/test/annotations/Fields.test.js.map +1 -1
- package/lib/esm/test/annotations/LeaderGeometry.test.js +12 -10
- package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
- package/lib/esm/test/annotations/TextAnnotation.test.js +299 -43
- package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
- package/lib/esm/test/annotations/TextBlock.test.js +453 -86
- package/lib/esm/test/annotations/TextBlock.test.js.map +1 -1
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts +46 -0
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts.map +1 -1
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js +20 -2
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js.map +1 -1
- package/lib/esm/test/ecdb/ECDb.test.js +71 -1
- package/lib/esm/test/ecdb/ECDb.test.js.map +1 -1
- package/lib/esm/test/hubaccess/Rebase.test.d.ts +2 -0
- package/lib/esm/test/hubaccess/Rebase.test.d.ts.map +1 -0
- package/lib/esm/test/hubaccess/Rebase.test.js +640 -0
- package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -0
- package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js +20 -20
- package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js +3 -3
- package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts +16 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js +47 -0
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js.map +1 -1
- package/lib/esm/test/standalone/ChangeMerge.test.js +15 -19
- package/lib/esm/test/standalone/ChangeMerge.test.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +131 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/lib/esm/test/standalone/MergeConflict.test.js +3 -3
- package/lib/esm/test/standalone/MergeConflict.test.js.map +1 -1
- package/lib/esm/workspace/Workspace.d.ts +1 -1
- package/lib/esm/workspace/Workspace.js.map +1 -1
- package/package.json +13 -13
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { expect } from "chai";
|
|
6
6
|
import { computeGraphemeOffsets, layoutTextBlock, TextStyleResolver } from "../../annotations/TextBlockLayout";
|
|
7
7
|
import { Geometry } from "@itwin/core-geometry";
|
|
8
|
-
import { ColorDef, FontType, FractionRun, LineBreakRun, Paragraph, TabRun, TextAnnotation, TextBlock, TextRun, TextStyleSettings } from "@itwin/core-common";
|
|
8
|
+
import { ColorDef, FontType, FractionRun, LineBreakRun, List, ListMarkerEnumerator, Paragraph, TabRun, TextAnnotation, TextBlock, TextRun, TextStyleSettings } from "@itwin/core-common";
|
|
9
9
|
import { IModelTestUtils } from "../IModelTestUtils";
|
|
10
10
|
import { ProcessDetector } from "@itwin/core-bentley";
|
|
11
11
|
import { produceTextBlockGeometry } from "../../core-backend";
|
|
@@ -28,11 +28,12 @@ function findTextStyleImpl(id) {
|
|
|
28
28
|
describe("layoutTextBlock", () => {
|
|
29
29
|
describe("resolves TextStyleSettings", () => {
|
|
30
30
|
it("inherits styling from TextBlock when Paragraph and Run have no style overrides", () => {
|
|
31
|
-
const textBlock = TextBlock.create(
|
|
31
|
+
const textBlock = TextBlock.create();
|
|
32
32
|
const run = TextRun.create({ content: "test" });
|
|
33
33
|
textBlock.appendParagraph();
|
|
34
34
|
textBlock.appendRun(run);
|
|
35
35
|
const tb = doLayout(textBlock, {
|
|
36
|
+
textStyleId: "0x42",
|
|
36
37
|
findTextStyle: findTextStyleImpl,
|
|
37
38
|
});
|
|
38
39
|
expect(tb.lines.length).to.equal(1);
|
|
@@ -43,12 +44,11 @@ describe("layoutTextBlock", () => {
|
|
|
43
44
|
expect(runStyle.isBold).to.be.true;
|
|
44
45
|
});
|
|
45
46
|
it("inherits style overrides from Paragraph when Run has no style overrides", () => {
|
|
46
|
-
const textBlock = TextBlock.create(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
textBlock.paragraphs.push(paragraph);
|
|
50
|
-
textBlock.appendRun(run);
|
|
47
|
+
const textBlock = TextBlock.create();
|
|
48
|
+
textBlock.appendParagraph({ styleOverrides: { fontName: "paragraph" } });
|
|
49
|
+
textBlock.appendRun(TextRun.create({ content: "test" }));
|
|
51
50
|
const tb = doLayout(textBlock, {
|
|
51
|
+
textStyleId: "0x42",
|
|
52
52
|
findTextStyle: findTextStyleImpl,
|
|
53
53
|
});
|
|
54
54
|
expect(tb.lines.length).to.equal(1);
|
|
@@ -58,12 +58,11 @@ describe("layoutTextBlock", () => {
|
|
|
58
58
|
expect(runStyle.isBold).to.be.true;
|
|
59
59
|
});
|
|
60
60
|
it("uses Run style overrides when Run has overrides", () => {
|
|
61
|
-
const textBlock = TextBlock.create(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
textBlock.paragraphs.push(paragraph);
|
|
65
|
-
textBlock.appendRun(run);
|
|
61
|
+
const textBlock = TextBlock.create();
|
|
62
|
+
textBlock.appendParagraph({ styleOverrides: { lineSpacingFactor: 55, fontName: "paragraph" } });
|
|
63
|
+
textBlock.appendRun(TextRun.create({ content: "test", styleOverrides: { lineSpacingFactor: 99, fontName: "run" } }));
|
|
66
64
|
const tb = doLayout(textBlock, {
|
|
65
|
+
textStyleId: "0x42",
|
|
67
66
|
findTextStyle: findTextStyleImpl,
|
|
68
67
|
});
|
|
69
68
|
expect(tb.lines.length).to.equal(1);
|
|
@@ -73,12 +72,13 @@ describe("layoutTextBlock", () => {
|
|
|
73
72
|
expect(runStyle.isBold).to.be.true;
|
|
74
73
|
});
|
|
75
74
|
it("still uses TextBlock specific styles when Run has style overrides", () => {
|
|
76
|
-
// Some style settings
|
|
77
|
-
const textBlock = TextBlock.create(
|
|
75
|
+
// Some style settings make sense on a TextBlock, so they are always applied from the TextBlock, even if the Run has a style override.
|
|
76
|
+
const textBlock = TextBlock.create();
|
|
78
77
|
const run = TextRun.create({ content: "test", styleOverrides: { lineSpacingFactor: 99, fontName: "run" } });
|
|
79
78
|
textBlock.appendParagraph();
|
|
80
79
|
textBlock.appendRun(run);
|
|
81
80
|
const tb = doLayout(textBlock, {
|
|
81
|
+
textStyleId: "0x42",
|
|
82
82
|
findTextStyle: findTextStyleImpl,
|
|
83
83
|
});
|
|
84
84
|
expect(tb.lines.length).to.equal(1);
|
|
@@ -87,10 +87,9 @@ describe("layoutTextBlock", () => {
|
|
|
87
87
|
expect(runStyle.lineSpacingFactor).to.equal(12);
|
|
88
88
|
});
|
|
89
89
|
it("inherits overrides from TextBlock, Paragraph and Run when there is no styleId", () => {
|
|
90
|
-
const textBlock = TextBlock.create({
|
|
91
|
-
const paragraph = Paragraph.create({ styleOverrides: { lineHeight: 56, color: 0xff0000, frame: { shape: "octagon" } } });
|
|
90
|
+
const textBlock = TextBlock.create({ styleOverrides: { widthFactor: 34, lineHeight: 3, lineSpacingFactor: 12, isBold: true } });
|
|
92
91
|
const run = TextRun.create({ content: "test", styleOverrides: { widthFactor: 78, fontName: "override", leader: { wantElbow: true } } });
|
|
93
|
-
textBlock.
|
|
92
|
+
textBlock.appendParagraph({ styleOverrides: { lineHeight: 56, color: 0xff0000, frame: { shape: "octagon" } } });
|
|
94
93
|
textBlock.appendRun(run);
|
|
95
94
|
const tb = doLayout(textBlock, {
|
|
96
95
|
findTextStyle: findTextStyleImpl,
|
|
@@ -113,12 +112,12 @@ describe("layoutTextBlock", () => {
|
|
|
113
112
|
expect(runStyle.isBold).to.be.true;
|
|
114
113
|
});
|
|
115
114
|
it("does not inherit overrides in TextBlock or Paragraph when Run has same propertied overriden - unless they are TextBlock specific settings", () => {
|
|
116
|
-
const textBlock = TextBlock.create({
|
|
117
|
-
const paragraph = Paragraph.create({ styleOverrides: { lineHeight: 56, color: 0xff0000 } });
|
|
115
|
+
const textBlock = TextBlock.create({ styleOverrides: { widthFactor: 34, lineHeight: 3, lineSpacingFactor: 12, isBold: true } });
|
|
118
116
|
const run = TextRun.create({ content: "test", styleOverrides: { widthFactor: 78, lineHeight: 6, lineSpacingFactor: 24, fontName: "override", isBold: false } });
|
|
119
|
-
textBlock.
|
|
117
|
+
textBlock.appendParagraph({ styleOverrides: { lineHeight: 56, color: 0xff0000 } });
|
|
120
118
|
textBlock.appendRun(run);
|
|
121
119
|
const tb = doLayout(textBlock, {
|
|
120
|
+
textStyleId: "0x42",
|
|
122
121
|
findTextStyle: findTextStyleImpl,
|
|
123
122
|
});
|
|
124
123
|
expect(tb.lines.length).to.equal(1);
|
|
@@ -136,10 +135,9 @@ describe("layoutTextBlock", () => {
|
|
|
136
135
|
});
|
|
137
136
|
it("takes child overrides over parent overrides", () => {
|
|
138
137
|
//...unless they are TextBlock specific as covered in other tests
|
|
139
|
-
const textBlock = TextBlock.create({
|
|
140
|
-
const paragraph = Paragraph.create({ styleOverrides: { fontName: "parent" } });
|
|
138
|
+
const textBlock = TextBlock.create({ styleOverrides: { fontName: "grandparent" } });
|
|
141
139
|
const run = TextRun.create({ content: "test", styleOverrides: { fontName: "child" } });
|
|
142
|
-
textBlock.
|
|
140
|
+
textBlock.appendParagraph({ styleOverrides: { fontName: "parent" } });
|
|
143
141
|
textBlock.appendRun(run);
|
|
144
142
|
const tb = doLayout(textBlock, {
|
|
145
143
|
findTextStyle: findTextStyleImpl,
|
|
@@ -155,7 +153,7 @@ describe("layoutTextBlock", () => {
|
|
|
155
153
|
this.skip();
|
|
156
154
|
}
|
|
157
155
|
// Initialize a new TextBlockLayout object
|
|
158
|
-
const textBlock = TextBlock.create({ width: 50,
|
|
156
|
+
const textBlock = TextBlock.create({ width: 50, styleOverrides: { widthFactor: 34, color: 0x00ff00, fontName: "arial" } });
|
|
159
157
|
const run0 = TextRun.create({
|
|
160
158
|
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium mi sit amet magna malesuada, at venenatis ante eleifend.",
|
|
161
159
|
styleOverrides: { lineHeight: 56, color: 0xff0000 },
|
|
@@ -194,8 +192,6 @@ describe("layoutTextBlock", () => {
|
|
|
194
192
|
for (let i = 0; i < result.lines.length; i++) {
|
|
195
193
|
const resultLine = result.lines[i];
|
|
196
194
|
const originalLine = textBlockLayout.lines[i];
|
|
197
|
-
// Source paragraph index matches
|
|
198
|
-
expect(resultLine.sourceParagraphIndex).to.equal(textBlock.paragraphs.indexOf(originalLine.source));
|
|
199
195
|
// Ranges match
|
|
200
196
|
expect(resultLine.range).to.deep.equal(originalLine.range.toJSON());
|
|
201
197
|
expect(resultLine.justificationRange).to.deep.equal(originalLine.justificationRange.toJSON());
|
|
@@ -204,8 +200,6 @@ describe("layoutTextBlock", () => {
|
|
|
204
200
|
for (let j = 0; j < resultLine.runs.length; j++) {
|
|
205
201
|
const resultRun = resultLine.runs[j];
|
|
206
202
|
const originalRun = originalLine.runs[j];
|
|
207
|
-
// Source run index matches
|
|
208
|
-
expect(resultRun.sourceRunIndex).to.equal(textBlock.paragraphs[resultLine.sourceParagraphIndex].runs.indexOf(originalRun.source));
|
|
209
203
|
// FontId matches
|
|
210
204
|
expect(resultRun.fontId).to.equal(originalRun.fontId);
|
|
211
205
|
// Offsets match
|
|
@@ -245,7 +239,7 @@ describe("layoutTextBlock", () => {
|
|
|
245
239
|
expect(resultRun.denominatorRange).to.deep.equal(originalRun.denominatorRange.toJSON());
|
|
246
240
|
}
|
|
247
241
|
// Check that the result string matches what we expect
|
|
248
|
-
const inputRun =
|
|
242
|
+
const inputRun = originalRun.source;
|
|
249
243
|
if (inputRun.type === "text") {
|
|
250
244
|
const resultText = inputRun.content.substring(resultRun.characterOffset, resultRun.characterOffset + resultRun.characterCount);
|
|
251
245
|
const originalText = inputRun.content.substring(originalRun.charOffset, originalRun.charOffset + originalRun.numChars);
|
|
@@ -262,7 +256,7 @@ describe("layoutTextBlock", () => {
|
|
|
262
256
|
expect(marginRange.high.y).to.equal(layoutRange.high.y + (margins.top ?? 0));
|
|
263
257
|
};
|
|
264
258
|
const makeTextBlock = (margins) => {
|
|
265
|
-
const textBlock = TextBlock.create({
|
|
259
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineSpacingFactor: 0 }, margins });
|
|
266
260
|
textBlock.appendRun(makeTextRun("abc"));
|
|
267
261
|
textBlock.appendRun(makeTextRun("defg"));
|
|
268
262
|
return textBlock;
|
|
@@ -287,7 +281,7 @@ describe("layoutTextBlock", () => {
|
|
|
287
281
|
});
|
|
288
282
|
describe("range", () => {
|
|
289
283
|
it("aligns text to center based on height of stacked fraction", () => {
|
|
290
|
-
const textBlock = TextBlock.create(
|
|
284
|
+
const textBlock = TextBlock.create();
|
|
291
285
|
const fractionRun = FractionRun.create({ numerator: "1", denominator: "2" });
|
|
292
286
|
const textRun = TextRun.create({ content: "text" });
|
|
293
287
|
textBlock.appendRun(fractionRun);
|
|
@@ -305,7 +299,9 @@ describe("layoutTextBlock", () => {
|
|
|
305
299
|
expect(round(textLayout.offsetFromLine.y, 3)).to.equal(.375);
|
|
306
300
|
});
|
|
307
301
|
it("produces one line per paragraph if document width <= 0", () => {
|
|
308
|
-
const
|
|
302
|
+
const lineSpacingFactor = 0.5;
|
|
303
|
+
const paragraphSpacingFactor = 0.25;
|
|
304
|
+
const textBlock = TextBlock.create({ styleOverrides: { paragraphSpacingFactor, lineSpacingFactor } });
|
|
309
305
|
for (let i = 0; i < 4; i++) {
|
|
310
306
|
const layout = doLayout(textBlock);
|
|
311
307
|
if (i === 0) {
|
|
@@ -314,7 +310,7 @@ describe("layoutTextBlock", () => {
|
|
|
314
310
|
else {
|
|
315
311
|
expect(layout.lines.length).to.equal(i);
|
|
316
312
|
expect(layout.range.low.x).to.equal(0);
|
|
317
|
-
expect(layout.range.low.y).to.equal(-i - (
|
|
313
|
+
expect(layout.range.low.y).to.equal(-i - ((i - 1) * (lineSpacingFactor + paragraphSpacingFactor)));
|
|
318
314
|
expect(layout.range.high.x).to.equal(i * 3);
|
|
319
315
|
expect(layout.range.high.y).to.equal(0);
|
|
320
316
|
}
|
|
@@ -336,14 +332,14 @@ describe("layoutTextBlock", () => {
|
|
|
336
332
|
}
|
|
337
333
|
const p = textBlock.appendParagraph();
|
|
338
334
|
for (let j = 0; j <= i; j++) {
|
|
339
|
-
p.
|
|
335
|
+
p.children.push(TextRun.create({ content: "Run" }));
|
|
340
336
|
}
|
|
341
337
|
}
|
|
342
338
|
});
|
|
343
339
|
it("produces a new line for each LineBreakRun", () => {
|
|
344
340
|
const lineSpacingFactor = 0.5;
|
|
345
341
|
const lineHeight = 1;
|
|
346
|
-
const textBlock = TextBlock.create({
|
|
342
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineSpacingFactor, lineHeight } });
|
|
347
343
|
textBlock.appendRun(TextRun.create({ content: "abc" }));
|
|
348
344
|
textBlock.appendRun(LineBreakRun.create());
|
|
349
345
|
textBlock.appendRun(TextRun.create({ content: "def" }));
|
|
@@ -358,12 +354,13 @@ describe("layoutTextBlock", () => {
|
|
|
358
354
|
expect(tb.range.low.x).to.equal(0);
|
|
359
355
|
expect(tb.range.high.x).to.equal(6);
|
|
360
356
|
expect(tb.range.high.y).to.equal(0);
|
|
357
|
+
// paragraphSpacingFactor should not be applied to linebreaks, but lineSpacingFactor should.
|
|
361
358
|
expect(tb.range.low.y).to.equal(-(lineSpacingFactor * 2 + lineHeight * 3));
|
|
362
359
|
});
|
|
363
360
|
it("applies tab shifts", () => {
|
|
364
361
|
const lineHeight = 1;
|
|
365
362
|
const tabInterval = 6;
|
|
366
|
-
const textBlock = TextBlock.create({
|
|
363
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineHeight, tabInterval } });
|
|
367
364
|
// Appends a line that looks like `stringOne` TAB `stringTwo` LINEBREAK
|
|
368
365
|
const appendLine = (stringOne, stringTwo, wantLineBreak = true) => {
|
|
369
366
|
if (stringOne.length > 0)
|
|
@@ -374,15 +371,15 @@ describe("layoutTextBlock", () => {
|
|
|
374
371
|
if (wantLineBreak)
|
|
375
372
|
textBlock.appendRun(LineBreakRun.create());
|
|
376
373
|
};
|
|
377
|
-
// The extra
|
|
378
|
-
appendLine("", "a");
|
|
379
|
-
appendLine("", "bc");
|
|
380
|
-
appendLine("a", "a");
|
|
381
|
-
appendLine("bc", "bc");
|
|
382
|
-
appendLine("cde", "cde");
|
|
383
|
-
appendLine("cdefg", "cde"); // this one is the max tab distance before needing to move to the next tab stop
|
|
384
|
-
appendLine("cdefgh", "cde"); // This one should push to the next tab stop.
|
|
385
|
-
appendLine("cdefghi", "cde", false); // This one should push to the next tab stop.
|
|
374
|
+
// The extra comments are intentional to show where the tab stops should be.
|
|
375
|
+
appendLine("", /*______*/ "a");
|
|
376
|
+
appendLine("", /*______*/ "bc");
|
|
377
|
+
appendLine("a", /*_____*/ "a");
|
|
378
|
+
appendLine("bc", /*____*/ "bc");
|
|
379
|
+
appendLine("cde", /*___*/ "cde");
|
|
380
|
+
appendLine("cdefg", /*_*/ "cde"); // this one is the max tab distance before needing to move to the next tab stop
|
|
381
|
+
appendLine("cdefgh", /*______*/ "cde"); // This one should push to the next tab stop.
|
|
382
|
+
appendLine("cdefghi", /*_____*/ "cde", false); // This one should push to the next tab stop.
|
|
386
383
|
const tb = doLayout(textBlock);
|
|
387
384
|
tb.lines.forEach((line, index) => {
|
|
388
385
|
const firstTextRun = (line.runs[0].source.type === "text") ? line.runs[0] : undefined;
|
|
@@ -395,7 +392,7 @@ describe("layoutTextBlock", () => {
|
|
|
395
392
|
it("applies consecutive tab shifts", () => {
|
|
396
393
|
const lineHeight = 1;
|
|
397
394
|
const tabInterval = 6;
|
|
398
|
-
const textBlock = TextBlock.create({
|
|
395
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineHeight, tabInterval } });
|
|
399
396
|
// line 0: ----->----->----->LINEBREAK
|
|
400
397
|
textBlock.appendRun(TabRun.create({ styleOverrides: { tabInterval } }));
|
|
401
398
|
textBlock.appendRun(TabRun.create({ styleOverrides: { tabInterval } }));
|
|
@@ -426,7 +423,7 @@ describe("layoutTextBlock", () => {
|
|
|
426
423
|
const line2 = tb.lines[2];
|
|
427
424
|
const line3 = tb.lines[3];
|
|
428
425
|
expect(line0.runs.length).to.equal(4);
|
|
429
|
-
expect(line0.range.xLength()).to.equal(3 * tabInterval, `Lines with
|
|
426
|
+
expect(line0.range.xLength()).to.equal(3 * tabInterval, `Lines with tabs should have the correct range length`);
|
|
430
427
|
expect(line1.runs.length).to.equal(4);
|
|
431
428
|
expect(line1.range.xLength()).to.equal(2 * tabInterval, `Tabs should be applied correctly when they are at the end of a line`);
|
|
432
429
|
expect(line2.runs.length).to.equal(5);
|
|
@@ -434,10 +431,12 @@ describe("layoutTextBlock", () => {
|
|
|
434
431
|
expect(line3.runs.length).to.equal(7);
|
|
435
432
|
expect(line3.range.xLength()).to.equal(7 + 3 + 7, `Multiple tabs with different intervals should be applied correctly`);
|
|
436
433
|
});
|
|
437
|
-
it("computes ranges based on custom line spacing
|
|
434
|
+
it("computes ranges based on custom line spacing, line height, and indentation", () => {
|
|
438
435
|
const lineSpacingFactor = 2;
|
|
439
436
|
const lineHeight = 3;
|
|
440
|
-
const
|
|
437
|
+
const paragraphSpacingFactor = 13;
|
|
438
|
+
const indentation = 7;
|
|
439
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineSpacingFactor, lineHeight, paragraphSpacingFactor, indentation } });
|
|
441
440
|
textBlock.appendRun(TextRun.create({ content: "abc" }));
|
|
442
441
|
textBlock.appendRun(LineBreakRun.create());
|
|
443
442
|
textBlock.appendRun(TextRun.create({ content: "def" }));
|
|
@@ -449,15 +448,85 @@ describe("layoutTextBlock", () => {
|
|
|
449
448
|
expect(tb.lines[0].runs.length).to.equal(2);
|
|
450
449
|
expect(tb.lines[1].runs.length).to.equal(3);
|
|
451
450
|
expect(tb.lines[2].runs.length).to.equal(1);
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
451
|
+
/* Final TextBlock should look like:
|
|
452
|
+
⇥abc↵
|
|
453
|
+
⇥defghi↵
|
|
454
|
+
⇥jkl
|
|
455
|
+
|
|
456
|
+
Where ↵ = LineBreak, ¶ = ParagraphBreak, ⇥ = indentation
|
|
457
|
+
|
|
458
|
+
We have 3 lines each `lineHeight` high, plus 2 line breaks in between each `lineHeight*lineSpacingFactor` high.
|
|
459
|
+
No paragraph spacing should be applied since there is one paragraph.
|
|
460
|
+
*/
|
|
461
|
+
expect(tb.range.low.x).to.equal(7);
|
|
462
|
+
expect(tb.range.high.x).to.equal(6 + 7); // 7 for indentation, 6 for the length of "defghi"
|
|
455
463
|
expect(tb.range.high.y).to.equal(0);
|
|
456
464
|
expect(tb.range.low.y).to.equal(-(lineHeight * 3 + (lineHeight * lineSpacingFactor) * 2));
|
|
457
465
|
expect(tb.lines[0].offsetFromDocument.y).to.equal(-lineHeight);
|
|
458
466
|
expect(tb.lines[1].offsetFromDocument.y).to.equal(tb.lines[0].offsetFromDocument.y - (lineHeight + lineHeight * lineSpacingFactor));
|
|
459
467
|
expect(tb.lines[2].offsetFromDocument.y).to.equal(tb.lines[1].offsetFromDocument.y - (lineHeight + lineHeight * lineSpacingFactor));
|
|
460
|
-
|
|
468
|
+
tb.lines.forEach((line) => expect(line.offsetFromDocument.x).to.equal(7));
|
|
469
|
+
});
|
|
470
|
+
it("computes paragraph spacing and indentation", () => {
|
|
471
|
+
const lineSpacingFactor = 2;
|
|
472
|
+
const lineHeight = 3;
|
|
473
|
+
const paragraphSpacingFactor = 13;
|
|
474
|
+
const indentation = 7;
|
|
475
|
+
const tabInterval = 5;
|
|
476
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineSpacingFactor, lineHeight, paragraphSpacingFactor, indentation, tabInterval } });
|
|
477
|
+
const p1 = textBlock.appendParagraph();
|
|
478
|
+
p1.children.push(TextRun.create({ content: "abc" })); // Line 1
|
|
479
|
+
p1.children.push(LineBreakRun.create());
|
|
480
|
+
p1.children.push(TextRun.create({ content: "def" })); // Line 2
|
|
481
|
+
const p2 = textBlock.appendParagraph();
|
|
482
|
+
p2.children.push(TextRun.create({ content: "ghi" })); // Line 3
|
|
483
|
+
const list = List.create();
|
|
484
|
+
list.children.push(Paragraph.create({ children: [{ type: "text", content: "list item 1" }] })); // Line 4
|
|
485
|
+
list.children.push(Paragraph.create({ children: [{ type: "text", content: "list item 2" }] })); // Line 5
|
|
486
|
+
list.children.push(Paragraph.create({ children: [{ type: "text", content: "list item 3" }] })); // Line 6
|
|
487
|
+
p2.children.push(list);
|
|
488
|
+
const tb = doLayout(textBlock);
|
|
489
|
+
expect(tb.lines.length).to.equal(6);
|
|
490
|
+
/* Final TextBlock should look like:
|
|
491
|
+
⇥abc↵
|
|
492
|
+
⇥def¶
|
|
493
|
+
⇥ghi¶
|
|
494
|
+
⇥→1. list item 1¶
|
|
495
|
+
⇥→2. list item 2¶
|
|
496
|
+
⇥→3. list item 3
|
|
497
|
+
|
|
498
|
+
Where ↵ = LineBreak, ¶ = ParagraphBreak, → = tabInterval/2, ⇥ = indentation
|
|
499
|
+
|
|
500
|
+
We have:
|
|
501
|
+
6 lines each `lineHeight` high
|
|
502
|
+
5 line breaks in between each `lineHeight*lineSpacingFactor` high
|
|
503
|
+
4 paragraph breaks in between each `lineHeight*paragraphSpacingFactor` high
|
|
504
|
+
*/
|
|
505
|
+
expect(tb.range.low.x).to.equal(7); // 7 for indentation
|
|
506
|
+
expect(tb.range.high.x).to.equal(7 + 5 + 11); // 7 for indentation, 5 for the tab stop, 11 for the length of "list item 1"
|
|
507
|
+
expect(tb.range.high.y).to.equal(0);
|
|
508
|
+
expect(tb.range.low.y).to.equal(-(lineHeight * 6 + (lineHeight * lineSpacingFactor) * 5 + (lineHeight * paragraphSpacingFactor) * 4));
|
|
509
|
+
// Cumulative vertical offsets to help make the test more readable.
|
|
510
|
+
let offsetY = -lineHeight;
|
|
511
|
+
let offsetX = indentation;
|
|
512
|
+
expect(tb.lines[0].offsetFromDocument.y).to.equal(offsetY);
|
|
513
|
+
expect(tb.lines[0].offsetFromDocument.x).to.equal(offsetX);
|
|
514
|
+
offsetY -= (lineHeight + lineHeight * lineSpacingFactor);
|
|
515
|
+
expect(tb.lines[1].offsetFromDocument.y).to.equal(offsetY);
|
|
516
|
+
expect(tb.lines[1].offsetFromDocument.x).to.equal(offsetX);
|
|
517
|
+
offsetY -= (lineHeight + lineHeight * lineSpacingFactor + lineHeight * paragraphSpacingFactor);
|
|
518
|
+
expect(tb.lines[2].offsetFromDocument.y).to.equal(offsetY);
|
|
519
|
+
expect(tb.lines[2].offsetFromDocument.x).to.equal(offsetX);
|
|
520
|
+
offsetX += tabInterval; // List items are indented using tabInterval.
|
|
521
|
+
offsetY -= (lineHeight + lineHeight * lineSpacingFactor + lineHeight * paragraphSpacingFactor);
|
|
522
|
+
expect(tb.lines[3].offsetFromDocument.y).to.equal(offsetY);
|
|
523
|
+
expect(tb.lines[3].offsetFromDocument.x).to.equal(offsetX);
|
|
524
|
+
offsetY -= (lineHeight + lineHeight * lineSpacingFactor + lineHeight * paragraphSpacingFactor);
|
|
525
|
+
expect(tb.lines[4].offsetFromDocument.y).to.equal(offsetY);
|
|
526
|
+
expect(tb.lines[4].offsetFromDocument.x).to.equal(offsetX);
|
|
527
|
+
offsetY -= (lineHeight + lineHeight * lineSpacingFactor + lineHeight * paragraphSpacingFactor);
|
|
528
|
+
expect(tb.lines[5].offsetFromDocument.y).to.equal(offsetY);
|
|
529
|
+
expect(tb.lines[5].offsetFromDocument.x).to.equal(offsetX);
|
|
461
530
|
});
|
|
462
531
|
function expectRange(width, height, range) {
|
|
463
532
|
expect(range.xLength()).to.equal(width);
|
|
@@ -467,7 +536,7 @@ describe("layoutTextBlock", () => {
|
|
|
467
536
|
if (!isIntlSupported()) {
|
|
468
537
|
this.skip();
|
|
469
538
|
}
|
|
470
|
-
const block = TextBlock.create({
|
|
539
|
+
const block = TextBlock.create({ width: 3, styleOverrides: { lineHeight: 1, lineSpacingFactor: 0 } });
|
|
471
540
|
function expectBlockRange(width, height) {
|
|
472
541
|
const layout = doLayout(block);
|
|
473
542
|
expectRange(width, height, layout.range);
|
|
@@ -491,7 +560,7 @@ describe("layoutTextBlock", () => {
|
|
|
491
560
|
if (!isIntlSupported()) {
|
|
492
561
|
this.skip();
|
|
493
562
|
}
|
|
494
|
-
const block = TextBlock.create({
|
|
563
|
+
const block = TextBlock.create({ styleOverrides: { lineHeight: 1, lineSpacingFactor: 0 } });
|
|
495
564
|
function expectBlockRange(width, height) {
|
|
496
565
|
const layout = doLayout(block);
|
|
497
566
|
expectRange(width, height, layout.range);
|
|
@@ -504,11 +573,145 @@ describe("layoutTextBlock", () => {
|
|
|
504
573
|
block.width = 10;
|
|
505
574
|
expectBlockRange(10, 2);
|
|
506
575
|
});
|
|
576
|
+
it("computes range for list markers and list items based on indentation", function () {
|
|
577
|
+
const lineSpacingFactor = 2;
|
|
578
|
+
const lineHeight = 3;
|
|
579
|
+
const paragraphSpacingFactor = 13;
|
|
580
|
+
const indentation = 7;
|
|
581
|
+
const tabInterval = 5;
|
|
582
|
+
const listChildren = [
|
|
583
|
+
{
|
|
584
|
+
children: [
|
|
585
|
+
{
|
|
586
|
+
type: "text",
|
|
587
|
+
content: "Oranges",
|
|
588
|
+
}
|
|
589
|
+
]
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
children: [
|
|
593
|
+
{
|
|
594
|
+
type: "text",
|
|
595
|
+
content: "Apples",
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
type: "list",
|
|
599
|
+
styleOverrides: { listMarker: { enumerator: ListMarkerEnumerator.Bullet } },
|
|
600
|
+
children: [
|
|
601
|
+
{
|
|
602
|
+
children: [
|
|
603
|
+
{
|
|
604
|
+
type: "text",
|
|
605
|
+
content: "Red",
|
|
606
|
+
}
|
|
607
|
+
]
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
children: [
|
|
611
|
+
{
|
|
612
|
+
type: "text",
|
|
613
|
+
content: "Green",
|
|
614
|
+
},
|
|
615
|
+
{
|
|
616
|
+
type: "list",
|
|
617
|
+
styleOverrides: { listMarker: { enumerator: ListMarkerEnumerator.RomanNumeral, case: "lower", terminator: "period" } },
|
|
618
|
+
children: [
|
|
619
|
+
{
|
|
620
|
+
children: [
|
|
621
|
+
{
|
|
622
|
+
type: "text",
|
|
623
|
+
content: "Granny Smith",
|
|
624
|
+
}
|
|
625
|
+
]
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
children: [
|
|
629
|
+
{
|
|
630
|
+
type: "text",
|
|
631
|
+
content: "Rhode Island Greening",
|
|
632
|
+
}
|
|
633
|
+
]
|
|
634
|
+
}
|
|
635
|
+
]
|
|
636
|
+
}
|
|
637
|
+
]
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
children: [
|
|
641
|
+
{
|
|
642
|
+
type: "text",
|
|
643
|
+
content: "Yellow",
|
|
644
|
+
}
|
|
645
|
+
]
|
|
646
|
+
}
|
|
647
|
+
]
|
|
648
|
+
}
|
|
649
|
+
]
|
|
650
|
+
}
|
|
651
|
+
];
|
|
652
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineSpacingFactor, lineHeight, paragraphSpacingFactor, indentation, tabInterval } });
|
|
653
|
+
const p1 = textBlock.appendParagraph();
|
|
654
|
+
p1.children.push(List.create({ children: listChildren }));
|
|
655
|
+
/* Final TextBlock should look like:
|
|
656
|
+
→1.→Oranges¶
|
|
657
|
+
→2.→Apples¶
|
|
658
|
+
→→•→Red¶
|
|
659
|
+
→→•→Green¶
|
|
660
|
+
→ →→i. →Granny Smith¶
|
|
661
|
+
→ →→ii.→Rhode Island Greening¶
|
|
662
|
+
→→•→Yellow
|
|
663
|
+
|
|
664
|
+
Where ↵ = LineBreak, ¶ = ParagraphBreak, → = tab, → = tabInterval/2, ⇥ = indentation
|
|
665
|
+
|
|
666
|
+
We have:
|
|
667
|
+
7 lines each `lineHeight` high
|
|
668
|
+
6 line breaks in between each `lineHeight*lineSpacingFactor` high
|
|
669
|
+
6 paragraph breaks in between each `lineHeight*paragraphSpacingFactor` high
|
|
670
|
+
*/
|
|
671
|
+
const tb = doLayout(textBlock);
|
|
672
|
+
expect(tb.lines.length).to.equal(7);
|
|
673
|
+
expect(tb.range.low.x).to.equal(7 + 5 - 5 / 2 - 2); // indentation + tabInterval - tabInterval/2 (for marker offset) + 2 (for the marker "1." justification, it's 2 characters wide)
|
|
674
|
+
expect(tb.range.high.x).to.equal(7 + 3 * 5 + 21); // 7 for indentation, 3 * 5 for the most nested tab stops, 21 for the length of "Rhode Island Greening"
|
|
675
|
+
expect(tb.range.high.y).to.equal(0);
|
|
676
|
+
expect(tb.range.low.y).to.equal(-(lineHeight * 7 + (lineHeight * lineSpacingFactor) * 6 + (lineHeight * paragraphSpacingFactor) * 6));
|
|
677
|
+
// Cumulative vertical offsets to help make the test more readable.
|
|
678
|
+
let offsetY = -lineHeight;
|
|
679
|
+
for (const line of tb.lines) {
|
|
680
|
+
expect(line.offsetFromDocument.y).to.equal(offsetY);
|
|
681
|
+
expect(line.marker).to.not.be.undefined;
|
|
682
|
+
expect(line.marker?.offsetFromLine.y).to.equal((lineHeight - line.marker.range.yLength()) / 2);
|
|
683
|
+
offsetY -= (lineHeight + lineHeight * lineSpacingFactor + lineHeight * paragraphSpacingFactor);
|
|
684
|
+
}
|
|
685
|
+
let markerXLength = tb.lines[0].marker.range.xLength();
|
|
686
|
+
let inset = indentation + tabInterval;
|
|
687
|
+
expect(tb.lines[0].offsetFromDocument.x).to.equal(inset); // →Oranges
|
|
688
|
+
expect(markerXLength).to.equal(2); // "1." is 2 characters wide
|
|
689
|
+
expect(tb.lines[0].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
690
|
+
markerXLength = tb.lines[1].marker.range.xLength();
|
|
691
|
+
expect(tb.lines[1].offsetFromDocument.x).to.equal(inset); // →Apples
|
|
692
|
+
expect(tb.lines[1].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
693
|
+
markerXLength = tb.lines[2].marker.range.xLength();
|
|
694
|
+
inset = indentation + tabInterval * 2;
|
|
695
|
+
expect(tb.lines[2].offsetFromDocument.x).to.equal(indentation + tabInterval * 2); // →→Red
|
|
696
|
+
expect(tb.lines[2].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
697
|
+
markerXLength = tb.lines[3].marker.range.xLength();
|
|
698
|
+
expect(tb.lines[3].offsetFromDocument.x).to.equal(indentation + tabInterval * 2); // →→Green
|
|
699
|
+
expect(tb.lines[3].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
700
|
+
markerXLength = tb.lines[4].marker.range.xLength();
|
|
701
|
+
expect(tb.lines[4].offsetFromDocument.x).to.equal(indentation + tabInterval * 3); // →→→Granny Smith
|
|
702
|
+
expect(tb.lines[4].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
703
|
+
markerXLength = tb.lines[5].marker.range.xLength();
|
|
704
|
+
expect(tb.lines[5].offsetFromDocument.x).to.equal(indentation + tabInterval * 3); // →→→Rhode Island Greening
|
|
705
|
+
expect(tb.lines[5].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
706
|
+
markerXLength = tb.lines[6].marker.range.xLength();
|
|
707
|
+
expect(tb.lines[6].offsetFromDocument.x).to.equal(indentation + tabInterval * 2); // →→Yellow
|
|
708
|
+
expect(tb.lines[6].marker.offsetFromLine.x).to.equal(0 - markerXLength - (tabInterval / 2));
|
|
709
|
+
});
|
|
507
710
|
it("justifies lines", function () {
|
|
508
711
|
if (!isIntlSupported()) {
|
|
509
712
|
this.skip();
|
|
510
713
|
}
|
|
511
|
-
const block = TextBlock.create({
|
|
714
|
+
const block = TextBlock.create({ styleOverrides: { lineSpacingFactor: 0 } });
|
|
512
715
|
function expectBlockRange(width, height) {
|
|
513
716
|
const layout = doLayout(block);
|
|
514
717
|
expectRange(width, height, layout.range);
|
|
@@ -582,12 +785,13 @@ describe("layoutTextBlock", () => {
|
|
|
582
785
|
});
|
|
583
786
|
describe("word-wrapping", () => {
|
|
584
787
|
function expectLines(input, width, expectedLines) {
|
|
585
|
-
const textBlock = TextBlock.create({
|
|
788
|
+
const textBlock = TextBlock.create({ styleOverrides: { paragraphSpacingFactor: 0, lineSpacingFactor: 0, lineHeight: 1 } });
|
|
586
789
|
textBlock.width = width;
|
|
587
790
|
const run = makeTextRun(input);
|
|
588
791
|
textBlock.appendRun(run);
|
|
589
792
|
const layout = doLayout(textBlock);
|
|
590
|
-
|
|
793
|
+
const content = run.stringify();
|
|
794
|
+
expect(layout.lines.every((line) => line.runs.every((r) => r.source.stringify() === content))).to.be.true;
|
|
591
795
|
const actual = layout.lines.map((line) => line.runs.map((runLayout) => runLayout.source.content.substring(runLayout.charOffset, runLayout.charOffset + runLayout.numChars)).join(""));
|
|
592
796
|
expect(actual).to.deep.equal(expectedLines);
|
|
593
797
|
return layout;
|
|
@@ -596,7 +800,7 @@ describe("layoutTextBlock", () => {
|
|
|
596
800
|
if (!isIntlSupported()) {
|
|
597
801
|
this.skip();
|
|
598
802
|
}
|
|
599
|
-
const textBlock = TextBlock.create(
|
|
803
|
+
const textBlock = TextBlock.create();
|
|
600
804
|
textBlock.width = 6;
|
|
601
805
|
textBlock.appendRun(makeTextRun("ab"));
|
|
602
806
|
expect(doLayout(textBlock).lines.length).to.equal(1);
|
|
@@ -685,7 +889,7 @@ describe("layoutTextBlock", () => {
|
|
|
685
889
|
this.skip();
|
|
686
890
|
}
|
|
687
891
|
const lineHeight = 1;
|
|
688
|
-
const textBlock = TextBlock.create({
|
|
892
|
+
const textBlock = TextBlock.create({ styleOverrides: { lineHeight } });
|
|
689
893
|
// line 0: -->-->------> LINEBREAK
|
|
690
894
|
textBlock.appendRun(TabRun.create({ styleOverrides: { tabInterval: 3 } }));
|
|
691
895
|
textBlock.appendRun(TabRun.create({ styleOverrides: { tabInterval: 3 } }));
|
|
@@ -755,7 +959,7 @@ describe("layoutTextBlock", () => {
|
|
|
755
959
|
if (!isIntlSupported()) {
|
|
756
960
|
this.skip();
|
|
757
961
|
}
|
|
758
|
-
const textBlock = TextBlock.create(
|
|
962
|
+
const textBlock = TextBlock.create();
|
|
759
963
|
for (const str of ["The ", "quick brown", " fox jumped over ", "the lazy ", "dog"]) {
|
|
760
964
|
textBlock.appendRun(makeTextRun(str));
|
|
761
965
|
}
|
|
@@ -799,7 +1003,7 @@ describe("layoutTextBlock", () => {
|
|
|
799
1003
|
if (!isIntlSupported()) {
|
|
800
1004
|
this.skip();
|
|
801
1005
|
}
|
|
802
|
-
const block = TextBlock.create(
|
|
1006
|
+
const block = TextBlock.create();
|
|
803
1007
|
block.appendRun(makeTextRun("aa")); // 2 chars wide
|
|
804
1008
|
block.appendRun(makeTextRun("bb ccc d ee")); // 11 chars wide
|
|
805
1009
|
block.appendRun(makeTextRun("ff ggg h")); // 8 chars wide
|
|
@@ -839,7 +1043,7 @@ describe("layoutTextBlock", () => {
|
|
|
839
1043
|
if (!isIntlSupported()) {
|
|
840
1044
|
this.skip();
|
|
841
1045
|
}
|
|
842
|
-
const block = TextBlock.create({
|
|
1046
|
+
const block = TextBlock.create({ styleOverrides: { lineHeight: 1, lineSpacingFactor: 0 } });
|
|
843
1047
|
block.appendRun(makeTextRun("abc defg"));
|
|
844
1048
|
const layout1 = doLayout(block);
|
|
845
1049
|
let width = layout1.range.xLength();
|
|
@@ -849,6 +1053,56 @@ describe("layoutTextBlock", () => {
|
|
|
849
1053
|
const layout2 = doLayout(block);
|
|
850
1054
|
expect(layout2.range.yLength()).to.equal(1);
|
|
851
1055
|
});
|
|
1056
|
+
it("wraps list items and applies indentation/insets for narrow text block width", function () {
|
|
1057
|
+
if (!isIntlSupported()) {
|
|
1058
|
+
this.skip();
|
|
1059
|
+
}
|
|
1060
|
+
const textBlock = TextBlock.create({ styleOverrides: { indentation: 2, tabInterval: 3, lineHeight: 1, lineSpacingFactor: 0, paragraphSpacingFactor: 0 } });
|
|
1061
|
+
/* Final TextBlock should look like:
|
|
1062
|
+
⇥→1.→Lorem ipsum dolor sit amet, consectetur adipiscing elit¶ | Inset by 5
|
|
1063
|
+
⇥→2.→sed do¶ | Inset by 5
|
|
1064
|
+
⇥→→a.→eiusmod tempor¶ | Inset by 8
|
|
1065
|
+
⇥→→b.→incididunt ut labore et dolore magna aliqua | Inset by 8
|
|
1066
|
+
|
|
1067
|
+
Where ↵ = LineBreak, ¶ = ParagraphBreak, → = tab, → = tabInterval/2, ⇥ = indentation
|
|
1068
|
+
*/
|
|
1069
|
+
// Create nested list structure
|
|
1070
|
+
const list = List.create();
|
|
1071
|
+
list.children.push(Paragraph.create({ children: [TextRun.create({ content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit" })] }));
|
|
1072
|
+
const apples = Paragraph.create({ children: [TextRun.create({ content: "sed do" })] });
|
|
1073
|
+
const subList = List.create({ styleOverrides: { listMarker: { enumerator: ListMarkerEnumerator.Letter, case: "lower", terminator: "period" } } });
|
|
1074
|
+
subList.children.push(Paragraph.create({ children: [TextRun.create({ content: "eiusmod tempor" })] }));
|
|
1075
|
+
subList.children.push(Paragraph.create({ children: [TextRun.create({ content: "incididunt ut labore et dolore magna aliqua" })] }));
|
|
1076
|
+
apples.children.push(subList);
|
|
1077
|
+
list.children.push(apples);
|
|
1078
|
+
textBlock.appendParagraph().children.push(list);
|
|
1079
|
+
function expectLayout(width, expected) {
|
|
1080
|
+
textBlock.width = width;
|
|
1081
|
+
const layout = doLayout(textBlock);
|
|
1082
|
+
// Check that each line is wrapped to width
|
|
1083
|
+
const minWidth = Math.max(19, width); // 19 for the width of the longest word with inset: "⇥→→b.→incididunt "
|
|
1084
|
+
if (width > 0) {
|
|
1085
|
+
layout.lines.forEach((line) => {
|
|
1086
|
+
expect(line.justificationRange.xLength() + line.offsetFromDocument.x).to.be.at.most(minWidth);
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
expect(layout.stringify()).to.equal(expected);
|
|
1090
|
+
// Top-level items should have indentation + tabInterval
|
|
1091
|
+
let inset = 2 + 3;
|
|
1092
|
+
layout.lines.forEach((line) => {
|
|
1093
|
+
if (line.stringify().includes("eiusmod"))
|
|
1094
|
+
inset += 3; // SubList items should have increased indentation
|
|
1095
|
+
expect(line.offsetFromDocument.x).to.equal(inset);
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
// Check indentation/insets for each line, indentation: 2, tabInterval: 5
|
|
1099
|
+
expectLayout(0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit\nsed do\neiusmod tempor\nincididunt ut labore et dolore magna aliqua");
|
|
1100
|
+
expectLayout(70, "Lorem ipsum dolor sit amet, consectetur adipiscing elit\nsed do\neiusmod tempor\nincididunt ut labore et dolore magna aliqua");
|
|
1101
|
+
expectLayout(40, "Lorem ipsum dolor sit amet, \nconsectetur adipiscing elit\nsed do\neiusmod tempor\nincididunt ut labore et dolore \nmagna aliqua");
|
|
1102
|
+
// TODO: layout should not pay attention to trailing whitespace when wrapping. I'll do this in another PR.
|
|
1103
|
+
expectLayout(21, "Lorem ipsum \ndolor sit amet, \nconsectetur \nadipiscing elit\nsed do\neiusmod \ntempor\nincididunt \nut labore et \ndolore magna \naliqua");
|
|
1104
|
+
expectLayout(15, "Lorem \nipsum \ndolor sit \namet, \nconsectetur \nadipiscing \nelit\nsed do\neiusmod \ntempor\nincididunt \nut \nlabore \net \ndolore \nmagna \naliqua");
|
|
1105
|
+
});
|
|
852
1106
|
});
|
|
853
1107
|
describe("grapheme offsets", () => {
|
|
854
1108
|
function getLayoutResultAndStyleResolver(textBlock) {
|
|
@@ -856,24 +1110,24 @@ describe("layoutTextBlock", () => {
|
|
|
856
1110
|
const result = layout.toResult();
|
|
857
1111
|
const textStyleResolver = new TextStyleResolver({
|
|
858
1112
|
textBlock,
|
|
1113
|
+
textStyleId: "",
|
|
859
1114
|
iModel: {},
|
|
860
|
-
modelId: undefined,
|
|
861
1115
|
findTextStyle: () => TextStyleSettings.defaults
|
|
862
1116
|
});
|
|
863
1117
|
return { textStyleResolver, result };
|
|
864
1118
|
}
|
|
865
1119
|
it("should return an empty array if source type is not text", function () {
|
|
866
|
-
const textBlock = TextBlock.create(
|
|
1120
|
+
const textBlock = TextBlock.create();
|
|
867
1121
|
const fractionRun = FractionRun.create({ numerator: "1", denominator: "2" });
|
|
868
1122
|
textBlock.appendRun(fractionRun);
|
|
869
1123
|
const { textStyleResolver, result } = getLayoutResultAndStyleResolver(textBlock);
|
|
1124
|
+
const source = textBlock.children[0]; // FractionRun is not a TextRun
|
|
870
1125
|
const args = {
|
|
871
|
-
|
|
1126
|
+
source,
|
|
872
1127
|
iModel: {},
|
|
873
1128
|
textStyleResolver,
|
|
874
1129
|
findFontId: () => 0,
|
|
875
1130
|
computeTextRange: computeTextRangeAsStringLength,
|
|
876
|
-
paragraphIndex: result.lines[0].sourceParagraphIndex,
|
|
877
1131
|
runLayoutResult: result.lines[0].runs[0],
|
|
878
1132
|
graphemeCharIndexes: [0],
|
|
879
1133
|
};
|
|
@@ -881,17 +1135,17 @@ describe("layoutTextBlock", () => {
|
|
|
881
1135
|
expect(graphemeRanges).to.be.an("array").that.is.empty;
|
|
882
1136
|
});
|
|
883
1137
|
it("should handle empty text content", function () {
|
|
884
|
-
const textBlock = TextBlock.create(
|
|
1138
|
+
const textBlock = TextBlock.create();
|
|
885
1139
|
const textRun = TextRun.create({ content: "" });
|
|
886
1140
|
textBlock.appendRun(textRun);
|
|
887
1141
|
const { textStyleResolver, result } = getLayoutResultAndStyleResolver(textBlock);
|
|
1142
|
+
const source = textBlock.children[0]; // FractionRun is not a TextRun
|
|
888
1143
|
const args = {
|
|
889
|
-
|
|
1144
|
+
source,
|
|
890
1145
|
iModel: {},
|
|
891
1146
|
textStyleResolver,
|
|
892
1147
|
findFontId: () => 0,
|
|
893
1148
|
computeTextRange: computeTextRangeAsStringLength,
|
|
894
|
-
paragraphIndex: result.lines[0].sourceParagraphIndex,
|
|
895
1149
|
runLayoutResult: result.lines[0].runs[0],
|
|
896
1150
|
graphemeCharIndexes: [0], // Supply a grapheme index even though there is no text
|
|
897
1151
|
};
|
|
@@ -899,17 +1153,17 @@ describe("layoutTextBlock", () => {
|
|
|
899
1153
|
expect(graphemeRanges).to.be.an("array").that.is.empty;
|
|
900
1154
|
});
|
|
901
1155
|
it("should compute grapheme offsets correctly for a given text", function () {
|
|
902
|
-
const textBlock = TextBlock.create(
|
|
1156
|
+
const textBlock = TextBlock.create();
|
|
903
1157
|
const textRun = TextRun.create({ content: "hello" });
|
|
904
1158
|
textBlock.appendRun(textRun);
|
|
905
1159
|
const { textStyleResolver, result } = getLayoutResultAndStyleResolver(textBlock);
|
|
1160
|
+
const source = textBlock.children[0].children[0];
|
|
906
1161
|
const args = {
|
|
907
|
-
|
|
1162
|
+
source,
|
|
908
1163
|
iModel: {},
|
|
909
1164
|
textStyleResolver,
|
|
910
1165
|
findFontId: () => 0,
|
|
911
1166
|
computeTextRange: computeTextRangeAsStringLength,
|
|
912
|
-
paragraphIndex: result.lines[0].sourceParagraphIndex,
|
|
913
1167
|
runLayoutResult: result.lines[0].runs[0],
|
|
914
1168
|
graphemeCharIndexes: [0, 1, 2, 3, 4],
|
|
915
1169
|
};
|
|
@@ -919,18 +1173,18 @@ describe("layoutTextBlock", () => {
|
|
|
919
1173
|
expect(graphemeRanges[4].high.x).to.equal(5);
|
|
920
1174
|
});
|
|
921
1175
|
it("should compute grapheme offsets correctly for non-English text", function () {
|
|
922
|
-
const textBlock = TextBlock.create(
|
|
1176
|
+
const textBlock = TextBlock.create();
|
|
923
1177
|
// Hindi - "Paragraph"
|
|
924
1178
|
const textRun = TextRun.create({ content: "अनुच्छेद" });
|
|
925
1179
|
textBlock.appendRun(textRun);
|
|
926
1180
|
const { textStyleResolver, result } = getLayoutResultAndStyleResolver(textBlock);
|
|
1181
|
+
const source = textBlock.children[0].children[0];
|
|
927
1182
|
const args = {
|
|
928
|
-
|
|
1183
|
+
source,
|
|
929
1184
|
iModel: {},
|
|
930
1185
|
textStyleResolver,
|
|
931
1186
|
findFontId: () => 0,
|
|
932
1187
|
computeTextRange: computeTextRangeAsStringLength,
|
|
933
|
-
paragraphIndex: result.lines[0].sourceParagraphIndex,
|
|
934
1188
|
runLayoutResult: result.lines[0].runs[0],
|
|
935
1189
|
graphemeCharIndexes: [0, 1, 3, 7],
|
|
936
1190
|
};
|
|
@@ -942,17 +1196,17 @@ describe("layoutTextBlock", () => {
|
|
|
942
1196
|
expect(graphemeRanges[3].high.x).to.equal(8);
|
|
943
1197
|
});
|
|
944
1198
|
it("should compute grapheme offsets correctly for emoji content", function () {
|
|
945
|
-
const textBlock = TextBlock.create(
|
|
1199
|
+
const textBlock = TextBlock.create();
|
|
946
1200
|
const textRun = TextRun.create({ content: "👨👦" });
|
|
947
1201
|
textBlock.appendRun(textRun);
|
|
948
1202
|
const { textStyleResolver, result } = getLayoutResultAndStyleResolver(textBlock);
|
|
1203
|
+
const source = textBlock.children[0].children[0];
|
|
949
1204
|
const args = {
|
|
950
|
-
|
|
1205
|
+
source,
|
|
951
1206
|
iModel: {},
|
|
952
1207
|
textStyleResolver,
|
|
953
1208
|
findFontId: () => 0,
|
|
954
1209
|
computeTextRange: computeTextRangeAsStringLength,
|
|
955
|
-
paragraphIndex: result.lines[0].sourceParagraphIndex,
|
|
956
1210
|
runLayoutResult: result.lines[0].runs[0],
|
|
957
1211
|
graphemeCharIndexes: [0],
|
|
958
1212
|
};
|
|
@@ -979,9 +1233,9 @@ describe("layoutTextBlock", () => {
|
|
|
979
1233
|
expect(comic).to.equal(3);
|
|
980
1234
|
expect(iModel.fonts.findId({ name: "Consolas" })).to.be.undefined;
|
|
981
1235
|
function test(fontName, expectedFontId) {
|
|
982
|
-
const textBlock = TextBlock.create(
|
|
1236
|
+
const textBlock = TextBlock.create();
|
|
983
1237
|
textBlock.appendRun(TextRun.create({ styleOverrides: { fontName } }));
|
|
984
|
-
const textStyleResolver = new TextStyleResolver({ textBlock, iModel });
|
|
1238
|
+
const textStyleResolver = new TextStyleResolver({ textBlock, textStyleId: "", iModel });
|
|
985
1239
|
const layout = layoutTextBlock({ textBlock, iModel, textStyleResolver });
|
|
986
1240
|
const run = layout.lines[0].runs[0];
|
|
987
1241
|
expect(run).not.to.be.undefined;
|
|
@@ -995,7 +1249,6 @@ describe("layoutTextBlock", () => {
|
|
|
995
1249
|
});
|
|
996
1250
|
function computeDimensions(args) {
|
|
997
1251
|
const textBlock = TextBlock.create({
|
|
998
|
-
styleId: "",
|
|
999
1252
|
styleOverrides: {
|
|
1000
1253
|
lineHeight: args.height,
|
|
1001
1254
|
widthFactor: args.width,
|
|
@@ -1009,7 +1262,7 @@ describe("layoutTextBlock", () => {
|
|
|
1009
1262
|
fontName: args.font ?? "Vera",
|
|
1010
1263
|
},
|
|
1011
1264
|
}));
|
|
1012
|
-
const textStyleResolver = new TextStyleResolver({ textBlock, iModel });
|
|
1265
|
+
const textStyleResolver = new TextStyleResolver({ textBlock, textStyleId: "", iModel });
|
|
1013
1266
|
const range = layoutTextBlock({ textBlock, iModel, textStyleResolver }).range;
|
|
1014
1267
|
return { x: range.high.x - range.low.x, y: range.high.y - range.low.y };
|
|
1015
1268
|
}
|
|
@@ -1085,7 +1338,7 @@ describe("produceTextBlockGeometry", () => {
|
|
|
1085
1338
|
return LineBreakRun.create({ styleOverrides });
|
|
1086
1339
|
}
|
|
1087
1340
|
function makeTextBlock(runs) {
|
|
1088
|
-
const block = TextBlock.create(
|
|
1341
|
+
const block = TextBlock.create();
|
|
1089
1342
|
for (const run of runs) {
|
|
1090
1343
|
block.appendRun(run);
|
|
1091
1344
|
}
|
|
@@ -1097,10 +1350,18 @@ describe("produceTextBlockGeometry", () => {
|
|
|
1097
1350
|
const layout = doLayout(block);
|
|
1098
1351
|
return produceTextBlockGeometry(layout, annotation.computeTransform(layout.range)).entries;
|
|
1099
1352
|
}
|
|
1353
|
+
function makeListGeometry(children) {
|
|
1354
|
+
const textBlock = TextBlock.create();
|
|
1355
|
+
const p1 = textBlock.appendParagraph();
|
|
1356
|
+
p1.children.push(List.create({ children }));
|
|
1357
|
+
const annotation = TextAnnotation.fromJSON({ textBlock: textBlock.toJSON() });
|
|
1358
|
+
const layout = doLayout(textBlock);
|
|
1359
|
+
return produceTextBlockGeometry(layout, annotation.computeTransform(layout.range)).entries;
|
|
1360
|
+
}
|
|
1100
1361
|
it("produces an empty array for an empty text block", () => {
|
|
1101
1362
|
expect(makeGeometry([])).to.deep.equal([]);
|
|
1102
1363
|
});
|
|
1103
|
-
it("produces an empty array for a block consisting
|
|
1364
|
+
it("produces an empty array for a block consisting of line breaks", () => {
|
|
1104
1365
|
expect(makeGeometry([makeBreak(), makeBreak(), makeBreak()])).to.deep.equal([]);
|
|
1105
1366
|
});
|
|
1106
1367
|
it("produces one appearance entry if all runs use subcategory color", () => {
|
|
@@ -1153,6 +1414,112 @@ describe("produceTextBlockGeometry", () => {
|
|
|
1153
1414
|
"text",
|
|
1154
1415
|
]);
|
|
1155
1416
|
});
|
|
1417
|
+
it("produces entries for list markers", () => {
|
|
1418
|
+
/* Final TextBlock should look like:
|
|
1419
|
+
1. Oranges // Oranges -> default "subcategory" text
|
|
1420
|
+
2. Apples // Apples -> Switch to red text
|
|
1421
|
+
• Red
|
|
1422
|
+
• Green // Green -> Switch to green text, not including the bullet.
|
|
1423
|
+
i. Granny Smith
|
|
1424
|
+
ii. Rhode Island Greening
|
|
1425
|
+
• Yellow // Yellow -> Back to red text
|
|
1426
|
+
|
|
1427
|
+
We have:
|
|
1428
|
+
7 lines each containing one TextString for the list marker and one for the text,
|
|
1429
|
+
4 appearance overrides
|
|
1430
|
+
*/
|
|
1431
|
+
const listChildren = [
|
|
1432
|
+
{
|
|
1433
|
+
children: [
|
|
1434
|
+
{
|
|
1435
|
+
type: "text",
|
|
1436
|
+
content: "Oranges",
|
|
1437
|
+
}
|
|
1438
|
+
]
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
children: [
|
|
1442
|
+
{
|
|
1443
|
+
type: "text",
|
|
1444
|
+
content: "Apples",
|
|
1445
|
+
},
|
|
1446
|
+
{
|
|
1447
|
+
type: "list",
|
|
1448
|
+
styleOverrides: { listMarker: { enumerator: ListMarkerEnumerator.Bullet }, color: ColorDef.red.tbgr },
|
|
1449
|
+
children: [
|
|
1450
|
+
{
|
|
1451
|
+
children: [
|
|
1452
|
+
{
|
|
1453
|
+
type: "text",
|
|
1454
|
+
content: "Red",
|
|
1455
|
+
}
|
|
1456
|
+
]
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
styleOverrides: { color: ColorDef.green.tbgr },
|
|
1460
|
+
children: [
|
|
1461
|
+
{
|
|
1462
|
+
type: "text",
|
|
1463
|
+
content: "Green",
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
type: "list",
|
|
1467
|
+
styleOverrides: { listMarker: { enumerator: ListMarkerEnumerator.RomanNumeral, case: "lower", terminator: "period" } },
|
|
1468
|
+
children: [
|
|
1469
|
+
{
|
|
1470
|
+
children: [
|
|
1471
|
+
{
|
|
1472
|
+
type: "text",
|
|
1473
|
+
content: "Granny Smith",
|
|
1474
|
+
}
|
|
1475
|
+
]
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
children: [
|
|
1479
|
+
{
|
|
1480
|
+
type: "text",
|
|
1481
|
+
content: "Rhode Island Greening",
|
|
1482
|
+
}
|
|
1483
|
+
]
|
|
1484
|
+
}
|
|
1485
|
+
]
|
|
1486
|
+
}
|
|
1487
|
+
]
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
children: [
|
|
1491
|
+
{
|
|
1492
|
+
type: "text",
|
|
1493
|
+
content: "Yellow",
|
|
1494
|
+
}
|
|
1495
|
+
]
|
|
1496
|
+
}
|
|
1497
|
+
]
|
|
1498
|
+
}
|
|
1499
|
+
]
|
|
1500
|
+
}
|
|
1501
|
+
];
|
|
1502
|
+
const entries = makeListGeometry(listChildren);
|
|
1503
|
+
expect(entries.length).to.equal(14 + 4); // 14 text strings + 4 appearance entry
|
|
1504
|
+
expect(entries[0].color).to.equal("subcategory");
|
|
1505
|
+
expect(entries[1].text?.text).to.equal("1.");
|
|
1506
|
+
expect(entries[2].text?.text).to.equal("Oranges");
|
|
1507
|
+
expect(entries[3].text?.text).to.equal("2.");
|
|
1508
|
+
expect(entries[4].text?.text).to.equal("Apples");
|
|
1509
|
+
expect(entries[5].color).to.equal(ColorDef.red.tbgr);
|
|
1510
|
+
expect(entries[6].text?.text).to.equal("•");
|
|
1511
|
+
expect(entries[7].text?.text).to.equal("Red");
|
|
1512
|
+
expect(entries[8].text?.text).to.equal("•");
|
|
1513
|
+
expect(entries[9].color).to.equal(ColorDef.green.tbgr);
|
|
1514
|
+
expect(entries[10].text?.text).to.equal("Green");
|
|
1515
|
+
expect(entries[11].text?.text).to.equal("i.");
|
|
1516
|
+
expect(entries[12].text?.text).to.equal("Granny Smith");
|
|
1517
|
+
expect(entries[13].text?.text).to.equal("ii.");
|
|
1518
|
+
expect(entries[14].text?.text).to.equal("Rhode Island Greening");
|
|
1519
|
+
expect(entries[15].color).to.equal(ColorDef.red.tbgr);
|
|
1520
|
+
expect(entries[16].text?.text).to.equal("•");
|
|
1521
|
+
expect(entries[17].text?.text).to.equal("Yellow");
|
|
1522
|
+
});
|
|
1156
1523
|
it("offsets geometry entries by margins", () => {
|
|
1157
1524
|
function makeGeometryWithMargins(anchor, margins) {
|
|
1158
1525
|
const runs = [makeText()];
|
|
@@ -1195,5 +1562,5 @@ describe("produceTextBlockGeometry", () => {
|
|
|
1195
1562
|
});
|
|
1196
1563
|
});
|
|
1197
1564
|
// Ignoring the text strings from the spell checker
|
|
1198
|
-
// cspell:ignore jklmnop vwxyz defg hijk ghij klmno pqrstu Tanuki aabb eeff nggg amet adipiscing elit Phasellus pretium malesuada venenatis eleifend Donec sapien Nullam commodo accumsan lacinia metus enim pharetra lacus facilisis Duis suscipit quis feugiat fermentum ut augue Mauris iaculis odio rhoncus lorem viverra turpis elementum posuere Consolas अनुच्छेद cdefg cdefgh cdefghi
|
|
1565
|
+
// cspell:ignore jklmnop vwxyz defg hijk ghij klmno pqrstu Tanuki aabb eeff nggg amet adipiscing elit Phasellus pretium malesuada venenatis eleifend Donec sapien Nullam commodo accumsan lacinia metus enim pharetra lacus facilisis Duis suscipit quis feugiat fermentum ut augue Mauris iaculis odio rhoncus lorem viverra turpis elementum posuere Consolas अनुच्छेद cdefg cdefgh cdefghi eiusmod tempor incididunt ut labore et dolore magna aliqua sed defghi
|
|
1199
1566
|
//# sourceMappingURL=TextBlock.test.js.map
|