fix: a figure frame stays in the middle of the column
An as-char text box takes its centring from the paragraph it is anchored in, and the importer lifts it out of that paragraph — so every figure in a fixture sat at the left margin. Carry style:horizontal-pos on the box (an image needs none: with no side to float to it centres anyway).
This commit is contained in:
1 parent
c26aac1bee
commit
615f2af52d
3 files changed
+23
-2
No files matched your search
@@ -38,6 +38,7 @@ export interface TextBoxAttrs {
|
||||
wrap: WrapMode;
|
||||
wrapOffset: number | null; // cm from the text column's left edge
|
||||
wrapOffsetY: number | null; // cm below the anchor paragraph
|
||||
wrapAlign: string | null; // 'center' = set against the middle of the column
|
||||
shapeKind: ShapeKind;
|
||||
fillColor: string | null;
|
||||
strokeColor: string | null;
|
||||
@@ -117,6 +118,13 @@ export const TextBox = Node.create({
|
||||
parseHTML: el => parseCmAttr((el as HTMLElement).getAttribute('data-wrap-offset-y')),
|
||||
renderHTML: () => ({}),
|
||||
},
|
||||
// 'center' = set against the middle of the column (ODF style:horizontal-pos): a
|
||||
// figure frame keeps it after the importer lifts it out of its anchor paragraph.
|
||||
wrapAlign: {
|
||||
default: null,
|
||||
parseHTML: el => (el as HTMLElement).getAttribute('data-wrap-align') || null,
|
||||
renderHTML: () => ({}),
|
||||
},
|
||||
shapeKind: {
|
||||
default: 'textbox',
|
||||
parseHTML: el => (el as HTMLElement).getAttribute('data-shape') ?? 'textbox',
|
||||
@@ -366,6 +374,11 @@ class TextBoxView {
|
||||
} else if (a.wrap === 'topBottom') {
|
||||
d.style.clear = 'both';
|
||||
}
|
||||
// Set against the middle of the column, unless the file placed it by coordinate.
|
||||
if (a.wrapAlign === 'center' && a.wrapOffset == null && a.wrap !== 'left' && a.wrap !== 'right') {
|
||||
d.style.marginLeft = 'auto';
|
||||
d.style.marginRight = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
// The resize/rotate handles and the badge — always ours, never ProseMirror's.
|
||||
|
||||
@@ -569,6 +569,7 @@ type TextBoxExport = {
|
||||
wrap: WrapMode;
|
||||
wrapOffsetCm: number | null;
|
||||
wrapOffsetYCm: number | null;
|
||||
wrapAlign: string | null;
|
||||
shapeKind: ShapeKind;
|
||||
fill: string | null;
|
||||
stroke: string | null;
|
||||
@@ -588,6 +589,7 @@ function textBoxDescriptor(node: TiptapNode): TextBoxExport {
|
||||
wrap: wrapAttr === 'left' || wrapAttr === 'right' || wrapAttr === 'topBottom' ? wrapAttr : 'inline',
|
||||
wrapOffsetCm: typeof a.wrapOffset === 'number' ? round3(a.wrapOffset) : null,
|
||||
wrapOffsetYCm: typeof a.wrapOffsetY === 'number' ? round3(a.wrapOffsetY) : null,
|
||||
wrapAlign: a.wrapAlign === 'center' ? 'center' : null,
|
||||
shapeKind: kind === 'roundRect' || kind === 'ellipse' ? kind : 'textbox',
|
||||
fill: typeof a.fillColor === 'string' && a.fillColor ? a.fillColor : null,
|
||||
stroke: typeof a.strokeColor === 'string' && a.strokeColor ? a.strokeColor : null,
|
||||
@@ -3022,9 +3024,11 @@ function textBoxGraphicStyle(box: TextBoxExport, index: number): string {
|
||||
const stroke = box.stroke
|
||||
? `draw:stroke="solid" svg:stroke-color="${normalizeColor(box.stroke) ?? '#000000'}" svg:stroke-width="${r3(box.strokeWidthPt)}pt"`
|
||||
: 'draw:stroke="none"';
|
||||
// An as-char frame keeps only its horizontal-pos: that is what centres a figure
|
||||
// frame, and the anchor paragraph this export mints carries no alignment.
|
||||
const wrap = box.wrap === 'inline'
|
||||
? ''
|
||||
: ` ${imageWrapProps(box.wrap, box.wrapOffsetCm)} style:number-wrapped-paragraphs="no-limit"` +
|
||||
? (box.wrapAlign === 'center' ? ' style:horizontal-pos="center" style:horizontal-rel="paragraph-content"' : '')
|
||||
: ` ${imageWrapProps(box.wrap, box.wrapOffsetCm, box.wrapAlign)} style:number-wrapped-paragraphs="no-limit"` +
|
||||
` style:horizontal-rel="paragraph-content"` +
|
||||
` style:vertical-pos="${box.wrapOffsetYCm != null ? 'from-top' : 'top'}" style:vertical-rel="paragraph"`;
|
||||
// auto-grow only for plain text boxes; a custom-shape needs both explicitly
|
||||
|
||||
@@ -344,6 +344,10 @@ function convertTextBoxFrame(frame: Element, textBoxEl: Element, ctx: Ctx): Node
|
||||
if (hCm != null) attrs.height = Math.round(cmToPx(hCm));
|
||||
const gp = ctx.resolver.graphicProps(frame.getAttributeNS(NS.draw, 'style-name'));
|
||||
applyFrameRotationAndWrap(frame, attrs, gp);
|
||||
// A box is a block of its own here, so the centring of a figure frame — which its
|
||||
// as-char anchor paragraph would otherwise give it — has to ride the box itself.
|
||||
// An image needs none: with no side to float to it is centred anyway.
|
||||
if (gp['style:horizontal-pos'] === 'center' && attrs.wrapOffset == null) attrs.wrapAlign = 'center';
|
||||
shapeStyleAttrs(gp, attrs, false);
|
||||
return { type: 'textBox', attrs, content: textBoxContent(Array.from(textBoxEl.children), ctx) };
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user