diff --git a/src/lib/editor/extensions/textBox.ts b/src/lib/editor/extensions/textBox.ts index 86874fb..01068f2 100644 --- a/src/lib/editor/extensions/textBox.ts +++ b/src/lib/editor/extensions/textBox.ts @@ -38,7 +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 + wrapAlign: string | null; // 'center'/'right' = set against the middle/far end paddingCm: number; // inset ring around the text (ODF fo:padding) shapeKind: ShapeKind; fillColor: string | null; @@ -383,10 +383,12 @@ 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') { + // Set against the middle or the far end of the column, unless the file placed the + // box by coordinate. + if ((a.wrapAlign === 'center' || a.wrapAlign === 'right') + && a.wrapOffset == null && a.wrap !== 'left' && a.wrap !== 'right') { d.style.marginLeft = 'auto'; - d.style.marginRight = 'auto'; + if (a.wrapAlign === 'center') d.style.marginRight = 'auto'; } } diff --git a/src/lib/export/odt.ts b/src/lib/export/odt.ts index 9598322..ba05ffe 100644 --- a/src/lib/export/odt.ts +++ b/src/lib/export/odt.ts @@ -590,7 +590,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, + wrapAlign: a.wrapAlign === 'center' || a.wrapAlign === 'right' ? a.wrapAlign : null, paddingCm: typeof a.paddingCm === 'number' ? round3(a.paddingCm) : TEXTBOX_PADDING_CM, shapeKind: kind === 'roundRect' || kind === 'ellipse' ? kind : 'textbox', fill: typeof a.fillColor === 'string' && a.fillColor ? a.fillColor : null, @@ -3029,7 +3029,7 @@ function textBoxGraphicStyle(box: TextBoxExport, index: number): string { // 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' - ? (box.wrapAlign === 'center' ? ' style:horizontal-pos="center" style:horizontal-rel="paragraph-content"' : '') + ? (box.wrapAlign ? ` style:horizontal-pos="${box.wrapAlign}" 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"`; diff --git a/src/lib/import/odt.ts b/src/lib/import/odt.ts index 47858d5..fe0fc5b 100644 --- a/src/lib/import/odt.ts +++ b/src/lib/import/odt.ts @@ -800,6 +800,17 @@ function convertBlocks(elements: Element[], ctx: Ctx, kind: BlockKind, boldByDef if (anchor && !(pending.length && anchorIsEmpty)) out.push(anchor); if (!pending.length) return; if (kind === 'body') { + // A box lifted out of its anchor paragraph keeps the alignment that paragraph gave + // it: an as-char figure frame is set against the middle of the column by the + // paragraph it sits in, not by anything of its own. + const align = anchor?.attrs?.textAlign; + if (align === 'center' || align === 'right') { + for (const b of pending) { + if (b.type === 'textBox' && b.attrs && b.attrs.wrapOffset == null && !b.attrs.wrapAlign) { + b.attrs.wrapAlign = align; + } + } + } out.push(...pending); } else { ctx.warnings.add('Text boxes nested in table cells or other text boxes were flattened');