@segnavia/idml 0.33.0 → 0.35.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/anchored-frames.js +81 -0
- package/dist/chapter-openings.js +16 -0
- package/dist/map-book.js +65 -14
- package/dist/master-regions.js +89 -0
- package/dist/masters.js +30 -67
- package/dist/model.d.ts +2 -1
- package/dist/model.js +13 -6
- package/dist/openers.js +2 -14
- package/dist/paragraph-box.js +123 -0
- package/dist/placements.js +20 -14
- package/dist/positioned-box.js +9 -1
- package/dist/report.d.ts +1 -0
- package/dist/report.js +16 -6
- package/dist/stories.js +39 -13
- package/dist/story-model.js +9 -1
- package/dist/style-mappings.js +20 -0
- package/dist/style-property-report.js +19 -16
- package/dist/styles.js +75 -34
- package/dist/swatch-color.js +5 -5
- package/dist/types.d.ts +21 -1
- package/dist/unsupported-elements.js +2 -1
- package/package.json +3 -3
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { formatRoundedNumber, logicalCornerRadii } from "./positioned-box.js";
|
|
2
|
+
import { resolveSwatchColor } from "./swatch-color.js";
|
|
3
|
+
//#region src/paragraph-box.ts
|
|
4
|
+
function enabled(value) {
|
|
5
|
+
return value?.trim().toLowerCase() === "true";
|
|
6
|
+
}
|
|
7
|
+
function number(values, mapped, name) {
|
|
8
|
+
if (!mapped.has(name)) return void 0;
|
|
9
|
+
const value = Number(values[name]);
|
|
10
|
+
return Number.isFinite(value) ? value : void 0;
|
|
11
|
+
}
|
|
12
|
+
function points(output, property, value) {
|
|
13
|
+
output.push(`${property}:${formatRoundedNumber(value)}pt`);
|
|
14
|
+
}
|
|
15
|
+
function optionalPoints(output, property, value, scale = 1) {
|
|
16
|
+
if (value !== void 0) points(output, property, value * scale);
|
|
17
|
+
}
|
|
18
|
+
function combinedPoints(output, property, base, adjustment, scale = 1) {
|
|
19
|
+
if (base === void 0 && adjustment === void 0) return;
|
|
20
|
+
points(output, property, (base ?? 0) + (adjustment ?? 0) * scale);
|
|
21
|
+
}
|
|
22
|
+
function padding(options, output, property, base, offset, offsetName) {
|
|
23
|
+
if (base === void 0 && offset === void 0) return;
|
|
24
|
+
const value = (base ?? 0) + (offset ?? 0);
|
|
25
|
+
if (value < 0) options.report.add(options.unsupported, offsetName, options.location);
|
|
26
|
+
points(output, property, Math.max(0, value));
|
|
27
|
+
}
|
|
28
|
+
function boxDeclarations(options, shaded, reset, output) {
|
|
29
|
+
const { values, mapped, direction } = options;
|
|
30
|
+
const top = shaded ? number(values, mapped, "ParagraphShadingTopOffset") : void 0;
|
|
31
|
+
const bottom = shaded ? number(values, mapped, "ParagraphShadingBottomOffset") : void 0;
|
|
32
|
+
const left = shaded ? number(values, mapped, "ParagraphShadingLeftOffset") : void 0;
|
|
33
|
+
const right = shaded ? number(values, mapped, "ParagraphShadingRightOffset") : void 0;
|
|
34
|
+
const before = number(values, mapped, "SpaceBefore");
|
|
35
|
+
const after = number(values, mapped, "SpaceAfter");
|
|
36
|
+
const startIndent = number(values, mapped, direction === "rtl" ? "RightIndent" : "LeftIndent");
|
|
37
|
+
const endIndent = number(values, mapped, direction === "rtl" ? "LeftIndent" : "RightIndent");
|
|
38
|
+
const startOffset = direction === "rtl" ? right : left;
|
|
39
|
+
const endOffset = direction === "rtl" ? left : right;
|
|
40
|
+
const startOffsetName = direction === "rtl" ? "ParagraphShadingRightOffset" : "ParagraphShadingLeftOffset";
|
|
41
|
+
const endOffsetName = direction === "rtl" ? "ParagraphShadingLeftOffset" : "ParagraphShadingRightOffset";
|
|
42
|
+
if (reset) {
|
|
43
|
+
points(output, "margin-block-start", before ?? 0);
|
|
44
|
+
points(output, "margin-block-end", after ?? 0);
|
|
45
|
+
points(output, "padding-block-start", 0);
|
|
46
|
+
points(output, "padding-block-end", 0);
|
|
47
|
+
points(output, "padding-inline-start", Math.max(0, startIndent ?? 0));
|
|
48
|
+
points(output, "padding-inline-end", Math.max(0, endIndent ?? 0));
|
|
49
|
+
points(output, "margin-inline-start", 0);
|
|
50
|
+
points(output, "margin-inline-end", 0);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
combinedPoints(output, "margin-block-start", before, top, -1);
|
|
54
|
+
combinedPoints(output, "margin-block-end", after, bottom, -1);
|
|
55
|
+
padding(options, output, "padding-block-start", void 0, top, "ParagraphShadingTopOffset");
|
|
56
|
+
padding(options, output, "padding-block-end", void 0, bottom, "ParagraphShadingBottomOffset");
|
|
57
|
+
padding(options, output, "padding-inline-start", startIndent, startOffset, startOffsetName);
|
|
58
|
+
padding(options, output, "padding-inline-end", endIndent, endOffset, endOffsetName);
|
|
59
|
+
optionalPoints(output, "margin-inline-start", startOffset, -1);
|
|
60
|
+
optionalPoints(output, "margin-inline-end", endOffset, -1);
|
|
61
|
+
}
|
|
62
|
+
const PHYSICAL_CORNERS = [
|
|
63
|
+
"TopLeft",
|
|
64
|
+
"TopRight",
|
|
65
|
+
"BottomLeft",
|
|
66
|
+
"BottomRight"
|
|
67
|
+
];
|
|
68
|
+
function cornerDeclarations(options, output) {
|
|
69
|
+
const { values, mapped, direction, report, unsupported, location } = options;
|
|
70
|
+
const radii = {
|
|
71
|
+
topLeft: void 0,
|
|
72
|
+
topRight: void 0,
|
|
73
|
+
bottomLeft: void 0,
|
|
74
|
+
bottomRight: void 0
|
|
75
|
+
};
|
|
76
|
+
for (const physical of PHYSICAL_CORNERS) {
|
|
77
|
+
const optionName = `ParagraphShading${physical}CornerOption`;
|
|
78
|
+
const option = values[optionName];
|
|
79
|
+
if (!option || option === "None" || option.endsWith("/None")) continue;
|
|
80
|
+
if (option !== "RoundedCorner" && !option.endsWith("/RoundedCorner")) {
|
|
81
|
+
report.add(unsupported, optionName, location);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const radius = number(values, mapped, `ParagraphShading${physical}CornerRadius`);
|
|
85
|
+
if (radius !== void 0) radii[`${physical[0]?.toLowerCase()}${physical.slice(1)}`] = radius;
|
|
86
|
+
}
|
|
87
|
+
for (const [property, radius] of Object.entries(logicalCornerRadii(radii, direction))) if (radius !== void 0) points(output, property, radius);
|
|
88
|
+
}
|
|
89
|
+
function reportUnmappedOptions(options) {
|
|
90
|
+
const { values, report, unsupported, location } = options;
|
|
91
|
+
if (values.ParagraphShadingWidth && !["ColumnWidth", "Column"].includes(values.ParagraphShadingWidth)) report.add(unsupported, "ParagraphShadingWidth", location);
|
|
92
|
+
if (values.ParagraphShadingTopOrigin && !["Ascent", "AscentTopOrigin"].includes(values.ParagraphShadingTopOrigin)) report.add(unsupported, "ParagraphShadingTopOrigin", location);
|
|
93
|
+
if (values.ParagraphShadingBottomOrigin && !["Descent", "DescentBottomOrigin"].includes(values.ParagraphShadingBottomOrigin)) report.add(unsupported, "ParagraphShadingBottomOrigin", location);
|
|
94
|
+
if (enabled(values.ParagraphShadingClipToFrame)) report.add(unsupported, "ParagraphShadingClipToFrame", location);
|
|
95
|
+
if (enabled(values.ParagraphShadingSuppressPrinting)) report.add(unsupported, "ParagraphShadingSuppressPrinting", location);
|
|
96
|
+
}
|
|
97
|
+
function paragraphBoxDeclarations(options) {
|
|
98
|
+
const { values, swatches, report, unsupported, location } = options;
|
|
99
|
+
const output = [];
|
|
100
|
+
const shaded = enabled(values.ParagraphShadingOn);
|
|
101
|
+
boxDeclarations(options, shaded, options.resetShading, output);
|
|
102
|
+
if (options.resetShading) {
|
|
103
|
+
output.push("background-color:transparent");
|
|
104
|
+
for (const property of Object.keys(logicalCornerRadii({
|
|
105
|
+
topLeft: 0,
|
|
106
|
+
topRight: 0,
|
|
107
|
+
bottomLeft: 0,
|
|
108
|
+
bottomRight: 0
|
|
109
|
+
}, options.direction))) points(output, property, 0);
|
|
110
|
+
}
|
|
111
|
+
if (!shaded) return output;
|
|
112
|
+
if (!values.ParagraphShadingColor) report.add(unsupported, "ParagraphShadingColor", location);
|
|
113
|
+
const color = values.ParagraphShadingColor ? resolveSwatchColor(values.ParagraphShadingColor, swatches, report, location, "text", "ParagraphShadingColor") : void 0;
|
|
114
|
+
if (color) {
|
|
115
|
+
const tint = Number(values.ParagraphShadingTint);
|
|
116
|
+
output.push(`background-color:${Number.isFinite(tint) && tint >= 0 && tint < 100 ? `color-mix(in srgb, ${color} ${tint}%, #fff)` : color}`);
|
|
117
|
+
}
|
|
118
|
+
cornerDeclarations(options, output);
|
|
119
|
+
reportUnmappedOptions(options);
|
|
120
|
+
return output;
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { paragraphBoxDeclarations };
|
package/dist/placements.js
CHANGED
|
@@ -11,10 +11,13 @@ const IDENTITY = [
|
|
|
11
11
|
0,
|
|
12
12
|
0
|
|
13
13
|
];
|
|
14
|
-
function
|
|
15
|
-
const values = (
|
|
14
|
+
function itemTransform(value) {
|
|
15
|
+
const values = (value ?? "").trim().split(/\s+/).map(Number);
|
|
16
16
|
return values.length === 6 && values.every(Number.isFinite) ? values : IDENTITY;
|
|
17
17
|
}
|
|
18
|
+
function transform(element) {
|
|
19
|
+
return itemTransform(attribute(element, "ItemTransform"));
|
|
20
|
+
}
|
|
18
21
|
function compose(parent, child) {
|
|
19
22
|
const [a, b, c, d, x, y] = parent;
|
|
20
23
|
const [e, f, g, h, u, v] = child;
|
|
@@ -27,19 +30,23 @@ function compose(parent, child) {
|
|
|
27
30
|
b * u + d * v + y
|
|
28
31
|
];
|
|
29
32
|
}
|
|
30
|
-
function
|
|
33
|
+
function applyTransform(value, point) {
|
|
31
34
|
return [value[0] * point[0] + value[2] * point[1] + value[4], value[1] * point[0] + value[3] * point[1] + value[5]];
|
|
32
35
|
}
|
|
36
|
+
function pointValue(value, fallback) {
|
|
37
|
+
const values = (value ?? "").trim().split(/\s+/).map(Number);
|
|
38
|
+
return values.length === 2 && values.every(Number.isFinite) ? values : fallback;
|
|
39
|
+
}
|
|
33
40
|
function pageArea(element) {
|
|
34
41
|
const value = (attribute(element, "GeometricBounds") ?? "").trim().split(/\s+/).map(Number);
|
|
35
42
|
if (value.length !== 4 || !value.every(Number.isFinite)) return void 0;
|
|
36
43
|
const [top, left, bottom, right] = value;
|
|
37
44
|
const matrix = transform(element);
|
|
38
45
|
return [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
applyTransform(matrix, [left, top]),
|
|
47
|
+
applyTransform(matrix, [right, top]),
|
|
48
|
+
applyTransform(matrix, [right, bottom]),
|
|
49
|
+
applyTransform(matrix, [left, bottom])
|
|
43
50
|
];
|
|
44
51
|
}
|
|
45
52
|
function placementBounds(points) {
|
|
@@ -54,7 +61,7 @@ function placementBounds(points) {
|
|
|
54
61
|
};
|
|
55
62
|
}
|
|
56
63
|
function frameBounds(element, matrix) {
|
|
57
|
-
return placementBounds(elements(element).map((candidate) => attribute(candidate, "Anchor")).filter((value) => value !== void 0).map((value) => value.trim().split(/\s+/).map(Number)).filter((value) => value.length === 2 && value.every(Number.isFinite)).map((point) =>
|
|
64
|
+
return placementBounds(elements(element).map((candidate) => attribute(candidate, "Anchor")).filter((value) => value !== void 0).map((value) => value.trim().split(/\s+/).map(Number)).filter((value) => value.length === 2 && value.every(Number.isFinite)).map((point) => applyTransform(matrix, point)));
|
|
58
65
|
}
|
|
59
66
|
function contains(area, [x, y]) {
|
|
60
67
|
let inside = false;
|
|
@@ -86,17 +93,16 @@ function framePlacement(element, matrix, location) {
|
|
|
86
93
|
};
|
|
87
94
|
}
|
|
88
95
|
function pointAttribute(element, name, fallback) {
|
|
89
|
-
|
|
90
|
-
return values.length === 2 && values.every(Number.isFinite) ? values : fallback;
|
|
96
|
+
return pointValue(attribute(element, name), fallback);
|
|
91
97
|
}
|
|
92
98
|
function polygonPlacement(element, matrix, location, group) {
|
|
93
99
|
const paths = elements(element, "GeometryPathType").flatMap((path) => {
|
|
94
100
|
const points = elements(path, "PathPointType").flatMap((candidate) => {
|
|
95
101
|
const anchor = pointAttribute(candidate, "Anchor");
|
|
96
102
|
return anchor ? [{
|
|
97
|
-
anchor:
|
|
98
|
-
left:
|
|
99
|
-
right:
|
|
103
|
+
anchor: applyTransform(matrix, anchor),
|
|
104
|
+
left: applyTransform(matrix, pointAttribute(candidate, "LeftDirection", anchor)),
|
|
105
|
+
right: applyTransform(matrix, pointAttribute(candidate, "RightDirection", anchor))
|
|
100
106
|
}] : [];
|
|
101
107
|
});
|
|
102
108
|
return points.length > 0 ? [{
|
|
@@ -297,4 +303,4 @@ function attachPlacements(placements, pageElements, pages, report) {
|
|
|
297
303
|
for (const item of placements.polygons) if (pageIndex(item.center) < 0) report.add(report.unsupportedElements, "polygon art group", item.polygon.location);
|
|
298
304
|
}
|
|
299
305
|
//#endregion
|
|
300
|
-
export { attachPlacements, contains, pageArea, placementBounds, spreadPlacements };
|
|
306
|
+
export { applyTransform, attachPlacements, contains, itemTransform, pageArea, placementBounds, pointValue, spreadPlacements };
|
package/dist/positioned-box.js
CHANGED
|
@@ -4,6 +4,14 @@ function formatRoundedNumber(value, digits = 2) {
|
|
|
4
4
|
const rounded = Number(value.toFixed(digits));
|
|
5
5
|
return String(Object.is(rounded, -0) ? 0 : rounded);
|
|
6
6
|
}
|
|
7
|
+
function logicalCornerRadii(corners, direction) {
|
|
8
|
+
return {
|
|
9
|
+
"border-start-start-radius": direction === "rtl" ? corners.topRight : corners.topLeft,
|
|
10
|
+
"border-start-end-radius": direction === "rtl" ? corners.topLeft : corners.topRight,
|
|
11
|
+
"border-end-start-radius": direction === "rtl" ? corners.bottomRight : corners.bottomLeft,
|
|
12
|
+
"border-end-end-radius": direction === "rtl" ? corners.bottomLeft : corners.bottomRight
|
|
13
|
+
};
|
|
14
|
+
}
|
|
7
15
|
function positionedBoxStyle(bounds, options) {
|
|
8
16
|
const scale = options.unit === "mm" ? MM_PER_PT : 1;
|
|
9
17
|
const digits = options.unit === "mm" ? 6 : 2;
|
|
@@ -11,4 +19,4 @@ function positionedBoxStyle(bounds, options) {
|
|
|
11
19
|
return `position:absolute;inset-inline-start:${value(options.rtl ? options.pageWidth - options.margin.right - bounds.right : bounds.left - options.margin.left)};inline-size:${value(bounds.right - bounds.left)};inset-block-start:${value(bounds.top - options.blockOrigin)};block-size:${value(bounds.bottom - bounds.top)}`;
|
|
12
20
|
}
|
|
13
21
|
//#endregion
|
|
14
|
-
export { formatRoundedNumber, positionedBoxStyle };
|
|
22
|
+
export { formatRoundedNumber, logicalCornerRadii, positionedBoxStyle };
|
package/dist/report.d.ts
CHANGED
package/dist/report.js
CHANGED
|
@@ -7,6 +7,7 @@ const BUCKET_NAMES = {
|
|
|
7
7
|
unsupportedLanguages: "language",
|
|
8
8
|
spotColors: "spot"
|
|
9
9
|
};
|
|
10
|
+
const KEYED_RECORD_NAMES = ["strippedAssetContent", "versoOpenings"];
|
|
10
11
|
function fontUseKey(appliedFont, fontStyle) {
|
|
11
12
|
return `${appliedFont}\u0000${fontStyle ?? ""}`;
|
|
12
13
|
}
|
|
@@ -16,6 +17,7 @@ var ReportCollector = class {
|
|
|
16
17
|
unmappedFonts = /* @__PURE__ */ new Map();
|
|
17
18
|
links = /* @__PURE__ */ new Map();
|
|
18
19
|
strippedAssetContent = /* @__PURE__ */ new Map();
|
|
20
|
+
versoOpenings = /* @__PURE__ */ new Map();
|
|
19
21
|
mixedMasterChapters;
|
|
20
22
|
buckets = Object.fromEntries(Object.keys(BUCKET_NAMES).map((name) => [name, /* @__PURE__ */ new Map()]));
|
|
21
23
|
get unsupportedElements() {
|
|
@@ -46,7 +48,7 @@ var ReportCollector = class {
|
|
|
46
48
|
for (const font of seed?.fonts ?? []) this.font(font.appliedFont, font.fontStyle, font.locations[0] ?? "Resources/Styles.xml");
|
|
47
49
|
for (const font of seed?.unmappedFonts ?? []) for (const location of font.locations) this.unmappedFont(font.appliedFont, font.fontStyle, location);
|
|
48
50
|
for (const link of seed?.links ?? []) for (const location of link.locations) this.link(link.uri, location);
|
|
49
|
-
for (const [
|
|
51
|
+
for (const name of KEYED_RECORD_NAMES) for (const [key, locations] of Object.entries(seed?.[name] ?? {})) for (const location of locations) this.recordKeyed(this[name], key, location);
|
|
50
52
|
}
|
|
51
53
|
add(bucket, name, location, count = 1) {
|
|
52
54
|
bucket.set(name, (bucket.get(name) ?? 0) + count);
|
|
@@ -76,9 +78,15 @@ var ReportCollector = class {
|
|
|
76
78
|
this.links.set(uri, found);
|
|
77
79
|
}
|
|
78
80
|
strippedAsset(uri, finding) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
this.recordKeyed(this.strippedAssetContent, uri, finding);
|
|
82
|
+
}
|
|
83
|
+
versoOpening(story, page) {
|
|
84
|
+
this.recordKeyed(this.versoOpenings, story, page);
|
|
85
|
+
}
|
|
86
|
+
recordKeyed(target, key, location) {
|
|
87
|
+
const found = target.get(key) ?? [];
|
|
88
|
+
this.recordLocation(found, location);
|
|
89
|
+
target.set(key, found);
|
|
82
90
|
}
|
|
83
91
|
record(target, appliedFont, fontStyle, location) {
|
|
84
92
|
const key = fontUseKey(appliedFont, fontStyle);
|
|
@@ -95,13 +103,15 @@ var ReportCollector = class {
|
|
|
95
103
|
}
|
|
96
104
|
data() {
|
|
97
105
|
const record = (values) => Object.fromEntries([...values].sort(([a], [b]) => a.localeCompare(b)));
|
|
106
|
+
const buckets = Object.fromEntries(Object.keys(BUCKET_NAMES).map((name) => [name, record(this.buckets[name])]));
|
|
107
|
+
const keyedRecords = Object.fromEntries(KEYED_RECORD_NAMES.map((name) => [name, Object.fromEntries([...this[name]].sort(([a], [b]) => a.localeCompare(b)))]));
|
|
98
108
|
return {
|
|
99
|
-
...
|
|
109
|
+
...buckets,
|
|
110
|
+
...keyedRecords,
|
|
100
111
|
locations: Object.fromEntries([...this.locations].sort(([a], [b]) => a.localeCompare(b))),
|
|
101
112
|
fonts: [...this.fonts.values()],
|
|
102
113
|
unmappedFonts: [...this.unmappedFonts.values()],
|
|
103
114
|
links: [...this.links.values()],
|
|
104
|
-
strippedAssetContent: Object.fromEntries([...this.strippedAssetContent].sort(([a], [b]) => a.localeCompare(b))),
|
|
105
115
|
mixedMasterChapters: [...this.mixedMasterChapters]
|
|
106
116
|
};
|
|
107
117
|
}
|
package/dist/stories.js
CHANGED
|
@@ -2,9 +2,9 @@ import { BOOK_FURNITURE, MOTIF_ATTRIBUTE, motifFieldAttribute, resolveDirection
|
|
|
2
2
|
import { Element, Text } from "domhandler";
|
|
3
3
|
import { BOOK_COLUMN_MAX, BOOK_COLUMN_MIN } from "@segnavia/html";
|
|
4
4
|
import serialize from "dom-serializer";
|
|
5
|
+
import { parseDocument } from "htmlparser2";
|
|
5
6
|
//#region src/stories.ts
|
|
6
7
|
const OMITTED = /* @__PURE__ */ new Set([
|
|
7
|
-
"TextFrame",
|
|
8
8
|
"Rectangle",
|
|
9
9
|
"Group",
|
|
10
10
|
"Polygon",
|
|
@@ -30,7 +30,7 @@ function rangeAttributes(node) {
|
|
|
30
30
|
function tokens(root, report) {
|
|
31
31
|
const result = [];
|
|
32
32
|
const terminal = (node, character) => {
|
|
33
|
-
if (node.name === "
|
|
33
|
+
if (node.name === "#text") result.push({
|
|
34
34
|
kind: "text",
|
|
35
35
|
text: node.text ?? "",
|
|
36
36
|
character,
|
|
@@ -52,6 +52,10 @@ function tokens(root, report) {
|
|
|
52
52
|
character,
|
|
53
53
|
location: node.location
|
|
54
54
|
});
|
|
55
|
+
else if (node.name === "TextFrame") result.push({
|
|
56
|
+
kind: "anchored",
|
|
57
|
+
location: node.location
|
|
58
|
+
});
|
|
55
59
|
else if (OMITTED.has(node.name)) report.add(report.unsupportedElements, node.name, node.location);
|
|
56
60
|
else if (node.name === "Properties") return true;
|
|
57
61
|
else if (node.name === "Change" && node.attributes.ChangeType !== void 0 && !node.attributes.ChangeType.includes("Inserted")) report.add(report.unsupportedElements, "Change", node.location);
|
|
@@ -59,6 +63,16 @@ function tokens(root, report) {
|
|
|
59
63
|
return true;
|
|
60
64
|
};
|
|
61
65
|
const walk = (node, character) => {
|
|
66
|
+
if (node.name === "Content") {
|
|
67
|
+
if (node.children.length === 0) result.push({
|
|
68
|
+
kind: "text",
|
|
69
|
+
text: node.text ?? "",
|
|
70
|
+
character,
|
|
71
|
+
location: node.location
|
|
72
|
+
});
|
|
73
|
+
else for (const child of node.children) walk(child, character);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
62
76
|
if (terminal(node, character)) return;
|
|
63
77
|
const nextCharacter = node.name === "CharacterStyleRange" ? node : character;
|
|
64
78
|
if (WRAPPERS.has(node.name)) report.add(report.unsupportedElements, node.name, node.location);
|
|
@@ -121,7 +135,7 @@ function furnitureNode(token, variables, master, styles, direction, report) {
|
|
|
121
135
|
if (master && variable) return markNode(variable, className);
|
|
122
136
|
report.add(report.unsupportedElements, variable ? `TextVariable:${variable.name}` : `TextVariableInstance:${token.variable ?? "unknown"}`, token.location);
|
|
123
137
|
}
|
|
124
|
-
function paragraphChildren(paragraphTokens, styles, report, direction, variables, master) {
|
|
138
|
+
function paragraphChildren(paragraphTokens, styles, report, direction, variables, master, options) {
|
|
125
139
|
const children = [];
|
|
126
140
|
let marked;
|
|
127
141
|
for (const token of paragraphTokens) {
|
|
@@ -143,6 +157,12 @@ function paragraphChildren(paragraphTokens, styles, report, direction, variables
|
|
|
143
157
|
continue;
|
|
144
158
|
}
|
|
145
159
|
marked = void 0;
|
|
160
|
+
if (token.kind === "anchored") {
|
|
161
|
+
const html = options.anchored?.(token.location, direction);
|
|
162
|
+
if (html) children.push(...parseDocument(html, { xmlMode: false }).children.filter((child) => child instanceof Text || child instanceof Element));
|
|
163
|
+
else if (!options.anchored) report.add(report.unsupportedElements, "TextFrame", token.location);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
146
166
|
const furniture = furnitureNode(token, variables, master, styles, direction, report);
|
|
147
167
|
if (furniture) children.push(furniture);
|
|
148
168
|
}
|
|
@@ -157,7 +177,7 @@ function textNodes(value) {
|
|
|
157
177
|
}
|
|
158
178
|
return result;
|
|
159
179
|
}
|
|
160
|
-
function paragraphNode(paragraph, paragraphTokens, styles, report, bookDirection, bookLanguage, storyDirection, frame, variables, master) {
|
|
180
|
+
function paragraphNode(paragraph, paragraphTokens, styles, report, bookDirection, bookLanguage, storyDirection, frame, variables, master, options) {
|
|
161
181
|
const attributes = rangeAttributes(paragraph);
|
|
162
182
|
const styleId = attributes.AppliedParagraphStyle;
|
|
163
183
|
const flattened = styles.flattened(styleId, "paragraph");
|
|
@@ -178,15 +198,21 @@ function paragraphNode(paragraph, paragraphTokens, styles, report, bookDirection
|
|
|
178
198
|
else report.addOnce(report.unsupportedElements, `TextColumnCount:${frame.columns}`, frame.location ?? paragraph.location);
|
|
179
199
|
}
|
|
180
200
|
if (span === "SplitColumns") report.add(report.unsupportedStyleProperties, "SpanColumnType:SplitColumns", paragraph.location);
|
|
181
|
-
const children = paragraphChildren(paragraphTokens, styles, report, resolvedDirection, variables, master);
|
|
201
|
+
const children = paragraphChildren(paragraphTokens, styles, report, resolvedDirection, variables, master, options);
|
|
182
202
|
if (children.length === 0) children.push(new Element("br", {}, []));
|
|
183
|
-
return new Element("p",
|
|
203
|
+
return new Element(options.inlineParagraphs ? "span" : "p", options.inlineParagraphs ? {
|
|
204
|
+
...htmlAttributes,
|
|
205
|
+
style: "display:block"
|
|
206
|
+
} : htmlAttributes, children);
|
|
184
207
|
}
|
|
185
|
-
function storyHtml(story, styles, report, bookDirection, bookLanguage) {
|
|
186
|
-
if (!story.root)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
208
|
+
function storyHtml(story, styles, report, bookDirection, bookLanguage, options = {}) {
|
|
209
|
+
if (!story.root) {
|
|
210
|
+
const empty = new Element(options.inlineParagraphs ? "span" : "p", options.inlineParagraphs ? { style: "display:block" } : {}, [new Element("br", {}, [])]);
|
|
211
|
+
return { html: serialize(empty, {
|
|
212
|
+
xmlMode: false,
|
|
213
|
+
encodeEntities: "utf8"
|
|
214
|
+
}) };
|
|
215
|
+
}
|
|
190
216
|
const paragraphs = [];
|
|
191
217
|
const paragraphRanges = [];
|
|
192
218
|
const collectParagraphs = (node) => {
|
|
@@ -198,14 +224,14 @@ function storyHtml(story, styles, report, bookDirection, bookLanguage) {
|
|
|
198
224
|
const all = tokens(paragraph, report);
|
|
199
225
|
let current = [];
|
|
200
226
|
const flush = () => {
|
|
201
|
-
paragraphs.push(paragraphNode(paragraph, current, styles, report, bookDirection, bookLanguage, story.direction, story.frame, story.textVariables ?? [], story.master ?? false));
|
|
227
|
+
paragraphs.push(paragraphNode(paragraph, current, styles, report, bookDirection, bookLanguage, story.direction, story.frame, story.textVariables ?? [], story.master ?? false, options));
|
|
202
228
|
current = [];
|
|
203
229
|
};
|
|
204
230
|
for (const token of all) if (token.kind === "paragraph") flush();
|
|
205
231
|
else current.push(token);
|
|
206
232
|
if (current.length > 0 || all.length === 0 || all.at(-1)?.kind !== "paragraph") flush();
|
|
207
233
|
}
|
|
208
|
-
if (paragraphs.length === 0) paragraphs.push(new Element("p", {}, [new Element("br", {}, [])]));
|
|
234
|
+
if (paragraphs.length === 0) paragraphs.push(new Element(options.inlineParagraphs ? "span" : "p", options.inlineParagraphs ? { style: "display:block" } : {}, [new Element("br", {}, [])]));
|
|
209
235
|
return {
|
|
210
236
|
html: serialize(paragraphs, {
|
|
211
237
|
xmlMode: false,
|
package/dist/story-model.js
CHANGED
|
@@ -5,9 +5,17 @@ import { isTag } from "domhandler";
|
|
|
5
5
|
function textNode(node, part, path) {
|
|
6
6
|
const children = [];
|
|
7
7
|
let childIndex = 0;
|
|
8
|
+
const content = localName(node.name) === "Content";
|
|
8
9
|
for (const child of node.children) {
|
|
9
10
|
childIndex += 1;
|
|
10
11
|
if (isTag(child)) children.push(textNode(child, part, `${path}/${localName(child.name)}[${childIndex}]`));
|
|
12
|
+
else if (child.type === "text" && content && child.data) children.push({
|
|
13
|
+
name: "#text",
|
|
14
|
+
attributes: {},
|
|
15
|
+
text: child.data,
|
|
16
|
+
children: [],
|
|
17
|
+
location: `${part}${path}#text${childIndex}`
|
|
18
|
+
});
|
|
11
19
|
else if (child.type === "directive") children.push({
|
|
12
20
|
name: "#processing-instruction",
|
|
13
21
|
attributes: {},
|
|
@@ -16,7 +24,7 @@ function textNode(node, part, path) {
|
|
|
16
24
|
location: `${part}${path}#pi${childIndex}`
|
|
17
25
|
});
|
|
18
26
|
}
|
|
19
|
-
const directText = node.children.filter((child) => child.type === "text").map((child) => child.data).join("");
|
|
27
|
+
const directText = content ? "" : node.children.filter((child) => child.type === "text").map((child) => child.data).join("");
|
|
20
28
|
return {
|
|
21
29
|
name: localName(node.name),
|
|
22
30
|
attributes: { ...node.attribs },
|
package/dist/style-mappings.js
CHANGED
|
@@ -24,6 +24,26 @@ const STYLE_PROPERTY_MAPPINGS = {
|
|
|
24
24
|
KeepFirstLines: css("keeps"),
|
|
25
25
|
KeepLastLines: css("keeps"),
|
|
26
26
|
StartParagraph: css("starts"),
|
|
27
|
+
ParagraphShadingOn: css("paragraph-shading"),
|
|
28
|
+
ParagraphShadingColor: css("paragraph-shading"),
|
|
29
|
+
ParagraphShadingTint: css("paragraph-shading"),
|
|
30
|
+
ParagraphShadingTopOffset: css("paragraph-shading"),
|
|
31
|
+
ParagraphShadingBottomOffset: css("paragraph-shading"),
|
|
32
|
+
ParagraphShadingLeftOffset: css("paragraph-shading"),
|
|
33
|
+
ParagraphShadingRightOffset: css("paragraph-shading"),
|
|
34
|
+
ParagraphShadingTopLeftCornerOption: css("paragraph-shading"),
|
|
35
|
+
ParagraphShadingTopLeftCornerRadius: css("paragraph-shading"),
|
|
36
|
+
ParagraphShadingTopRightCornerOption: css("paragraph-shading"),
|
|
37
|
+
ParagraphShadingTopRightCornerRadius: css("paragraph-shading"),
|
|
38
|
+
ParagraphShadingBottomLeftCornerOption: css("paragraph-shading"),
|
|
39
|
+
ParagraphShadingBottomLeftCornerRadius: css("paragraph-shading"),
|
|
40
|
+
ParagraphShadingBottomRightCornerOption: css("paragraph-shading"),
|
|
41
|
+
ParagraphShadingBottomRightCornerRadius: css("paragraph-shading"),
|
|
42
|
+
ParagraphShadingWidth: css("paragraph-shading"),
|
|
43
|
+
ParagraphShadingTopOrigin: css("paragraph-shading"),
|
|
44
|
+
ParagraphShadingBottomOrigin: css("paragraph-shading"),
|
|
45
|
+
ParagraphShadingClipToFrame: css("paragraph-shading"),
|
|
46
|
+
ParagraphShadingSuppressPrinting: css("paragraph-shading"),
|
|
27
47
|
ParagraphDirection: { kind: "direction" },
|
|
28
48
|
AppliedLanguage: { kind: "language" },
|
|
29
49
|
AppliedFont: { kind: "font" },
|
|
@@ -99,11 +99,6 @@ const SWITCHED_GROUPS = [
|
|
|
99
99
|
enabled: (values) => truthy(values.ParagraphBorderOn),
|
|
100
100
|
reportAs: "ParagraphBorderOn"
|
|
101
101
|
},
|
|
102
|
-
{
|
|
103
|
-
matches: (name) => name.startsWith("ParagraphShading"),
|
|
104
|
-
enabled: (values) => truthy(values.ParagraphShadingOn),
|
|
105
|
-
reportAs: "ParagraphShadingOn"
|
|
106
|
-
},
|
|
107
102
|
{
|
|
108
103
|
matches: (name) => name.startsWith("Underline"),
|
|
109
104
|
enabled: (values) => truthy(values.Underline) || values.Underline === "Underline",
|
|
@@ -192,6 +187,22 @@ function activeIdmlValue(value) {
|
|
|
192
187
|
function isHyphenationProperty(name) {
|
|
193
188
|
return name.startsWith("Hyphenat") || name === "HyphenWeight" || name === "ProviderHyphenationStyle";
|
|
194
189
|
}
|
|
190
|
+
function alwaysHandledElsewhere(name) {
|
|
191
|
+
return isHyphenationProperty(name) || JUSTIFICATION_SETTINGS.has(name) || [
|
|
192
|
+
"EmptyGrepStyles",
|
|
193
|
+
"EmptyNestedStyles",
|
|
194
|
+
"EmptyLineStyles"
|
|
195
|
+
].includes(name);
|
|
196
|
+
}
|
|
197
|
+
const COLLECTION_PROPERTIES = /* @__PURE__ */ new Set([
|
|
198
|
+
"AllGREPStyles",
|
|
199
|
+
"AllNestedStyles",
|
|
200
|
+
"AllLineStyles",
|
|
201
|
+
"TabList"
|
|
202
|
+
]);
|
|
203
|
+
function isCollectionProperty(name) {
|
|
204
|
+
return COLLECTION_PROPERTIES.has(name);
|
|
205
|
+
}
|
|
195
206
|
function groupedProperties(names, resolved) {
|
|
196
207
|
const output = [];
|
|
197
208
|
if (names.some(isHyphenationProperty) && truthy(resolved.Hyphenation)) output.push("Hyphenation");
|
|
@@ -204,17 +215,9 @@ function groupedProperties(names, resolved) {
|
|
|
204
215
|
}
|
|
205
216
|
function reportableProperty(name, value, resolved, root) {
|
|
206
217
|
if (stylePropertyMapping(name)) return void 0;
|
|
207
|
-
if (
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
"EmptyNestedStyles",
|
|
211
|
-
"EmptyLineStyles"
|
|
212
|
-
].includes(name)) return void 0;
|
|
213
|
-
if ([
|
|
214
|
-
"AllGREPStyles",
|
|
215
|
-
"AllNestedStyles",
|
|
216
|
-
"AllLineStyles"
|
|
217
|
-
].includes(name) || name === "TabList") return hasEntries(value) ? name : void 0;
|
|
218
|
+
if (alwaysHandledElsewhere(name)) return void 0;
|
|
219
|
+
if (isCollectionProperty(name)) return hasEntries(value) ? name : void 0;
|
|
220
|
+
if (name.startsWith("ParagraphShading")) return truthy(resolved.ParagraphShadingOn) && activeIdmlValue(value) ? name : void 0;
|
|
218
221
|
const switched = SWITCHED_GROUPS.find((group) => group.matches(name));
|
|
219
222
|
if (switched) return switched.enabled(resolved) ? switched.reportAs : void 0;
|
|
220
223
|
if ((CJK_PREFIXES.some((prefix) => name.startsWith(prefix)) || CJK_PROPERTIES.has(name)) && !isCjkLanguage(resolved.AppliedLanguage)) return void 0;
|