UNPKG

devexpress-richedit

Version:

DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.

721 lines (720 loc) 42.4 kB
import { UnitConverter } from '@devexpress/utils/lib/class/unit-converter'; import { FixedInterval } from '@devexpress/utils/lib/intervals/fixed'; import { ColorUtils } from '@devexpress/utils/lib/utils/color'; import { EncodeUtils } from '@devexpress/utils/lib/utils/encode'; import { SearchUtils } from '@devexpress/utils/lib/utils/search'; import { StringUtils } from '@devexpress/utils/lib/utils/string'; import { RichEditUnit } from '../../../utils/unit-converter'; import { LayoutPictureBox } from '../../../layout/main-structures/layout-boxes/layout-picture-box'; import { BorderLineStyle } from '../../../model/borders/enums'; import { CharacterProperties } from '../../../model/character/character-properties'; import { CharacterFormattingScript, UnderlineType } from '../../../model/character/enums'; import { ColorHelper } from '../../../model/color/color'; import { Field } from '../../../model/fields/field'; import { NumberingFormat } from '../../../model/numbering-lists/list-level-properties'; import { NumberingType } from '../../../model/numbering-lists/numbering-list'; import { ParagraphAlignment, ParagraphFirstLineIndent, ParagraphLineSpacingType, } from '../../../model/paragraph/paragraph-properties'; import { RichUtils } from '../../../model/rich-utils'; import { RunType } from '../../../model/runs/run-type'; import { Table } from '../../../model/tables/main-structures/table'; import { TableCellPropertiesMergerShadingInfo, TableCellVerticalAlignmentMerger, } from '../../../model/tables/properties-mergers/table-cell-properties-merger'; import { TablePropertiesMergerBorderHorizontal, TablePropertiesMergerBorderVertical, TablePropertiesMergerCellSpacing, TablePropertiesMergerIndent, } from '../../../model/tables/properties-mergers/table-properties-merger'; import { ConditionalTableStyleFormatting, TableCellMergingState, TableCellVerticalAlignment, } from '../../../model/tables/secondary-structures/table-base-structures'; import { TableWidthUnitType } from '../../../model/tables/secondary-structures/table-units'; import { HtmlConverter } from '../../../rich-utils/html-converter'; import { HtmlBuilder } from './html-builder'; import { isDefined } from '@devexpress/utils/lib/utils/common'; import { createUrlValidationOptions, UrlUtils } from '../../../../common/utils/utils'; import { ListUtils } from '@devexpress/utils/lib/utils/list'; export class HtmlExporter { get modelManager() { return this.exportModelOptions.modelManager; } get colorProvider() { return this.modelManager.model.colorProvider; } get unitConverter() { return this.exportModelOptions.uiUnitConverter; } get documentRenderer() { return this.exportModelOptions.pictureRenderer; } get lastMaxNumPages() { return this.exportModelOptions.lastMaxNumPages; } ; get pageIndex() { return this.exportModelOptions.pageIndex; } ; constructor(exportModelOptions, htmlExporterOptions = null) { this.rangeCopy = null; this.exportModelOptions = exportModelOptions; this.htmlExporterOptions = htmlExporterOptions; } getHtmlElementsByInterval(model, subDocument, interval, guidLabel) { var _a, _b, _c, _d; if (interval.length === 0) return; const unitTypeToString = this.unitConverter.getUnits() == RichEditUnit.Centimeter ? "cm" : "in"; const iterator = subDocument.getConstRunIterator(interval); let remainLength = interval.length; let currentPosition = interval.start; let resultBuilder = new HtmlBuilder(); const paragraphs = this.getParagraphsByInterval(subDocument, interval); const lists = this.getListsByParagraphs(paragraphs); let isInsideFieldCode = false; let fieldDeep = 0; let isInsideHyperlink = false; let hyperlinkInfo = null; let hyperlinkInnerHtml = new HtmlBuilder(); let hasFields = false; while (iterator.moveNext()) { const tableCell = Table.getTableCellByPosition(subDocument.tables, iterator.currentInterval().start); const isContinueMergingCell = tableCell && tableCell.verticalMerging === TableCellMergingState.Continue; const run = iterator.currentRun; const isRunInEmptyParagraph = run.paragraph.length === 1; if (paragraphs.length && (run.getType() != RunType.ParagraphRun || isRunInEmptyParagraph)) { const paragraphToStartIndex = SearchUtils.normedInterpolationIndexOf(paragraphs, (p) => p.startLogPosition.value, currentPosition); if (paragraphToStartIndex > -1) { const currentParagraph = paragraphs[paragraphToStartIndex]; paragraphs.splice(paragraphToStartIndex, 1); if (tableCell) { const row = tableCell.parentRow; const table = row.parentTable; const paragraphStartPosition = currentParagraph.startLogPosition.value; if (table.getStartPosition() == paragraphStartPosition) { if (table.parentCell) this.addParentTableRecursively(model, resultBuilder, table.parentCell, paragraphStartPosition); resultBuilder .startChild('table') .configure((el) => { el.style.cssText = this.getTableStyle(model, table); }) .startChild('tbody'); } if (row.getStartPosition() == paragraphStartPosition) { resultBuilder.startChild('tr'); if (row.gridBefore > 0) { resultBuilder .startChild('td') .configure((el) => { el.style.cssText = "mso-cell-special:placeholder"; el.setAttribute('colspan', row.gridBefore.toString()); el.innerHTML = "&nbsp;"; }) .endChild('td'); } } if (tableCell.startParagraphPosition.value == paragraphStartPosition && !isContinueMergingCell) { let rowSpan = 1; if (tableCell.verticalMerging === TableCellMergingState.Restart) { let rowIndex = table.rows.indexOf(row); let cellIndex = row.cells.indexOf(tableCell); for (let i = rowIndex + 1, row; row = table.rows[i]; i++) { let nextRowCellIndex = cellIndex; if (row.cells.length != row.cells.length) { let extraCellsCount = 0; let isNextRowLonger = row.cells.length > row.cells.length; let shorterRow = isNextRowLonger ? row : row; for (let j = 0; (j < cellIndex) && (j < shorterRow.cells.length); j++) { extraCellsCount += shorterRow.cells[j].columnSpan - 1; if (!isNextRowLonger) extraCellsCount -= row.cells[j].columnSpan - 1; } nextRowCellIndex += (isNextRowLonger ? 1 : -1) * extraCellsCount; } let nextRowCell = row.cells[nextRowCellIndex]; if (nextRowCell && nextRowCell.verticalMerging === TableCellMergingState.Continue) rowSpan++; else break; } } resultBuilder .startChild('td') .configure((el) => { el.style.cssText = this.getCellStyle(model, tableCell); if (rowSpan > 1) el.setAttribute('rowspan', rowSpan.toString()); if (tableCell.columnSpan > 1) el.setAttribute('colspan', tableCell.columnSpan.toString()); }); } } this.startList(model, subDocument, interval, resultBuilder, lists, iterator.currentInterval().start); if (!isContinueMergingCell) { const maskedParagraphProperties = currentParagraph.getParagraphMergedProperties(); let paragraphStyle = ""; const firstLineIndentType = maskedParagraphProperties.firstLineIndentType; if (firstLineIndentType != ParagraphFirstLineIndent.None) { paragraphStyle += "text-indent: " + (firstLineIndentType == ParagraphFirstLineIndent.Hanging ? "-" : "") + this.unitConverter.twipsToUI(maskedParagraphProperties.firstLineIndent) + unitTypeToString + ";"; } if (maskedParagraphProperties.alignment !== undefined) { paragraphStyle += "text-align: "; switch (maskedParagraphProperties.alignment) { case ParagraphAlignment.Left: paragraphStyle += "left;"; break; case ParagraphAlignment.Right: paragraphStyle += "right;"; break; case ParagraphAlignment.Justify: case ParagraphAlignment.JustifyHigh: case ParagraphAlignment.JustifyLow: case ParagraphAlignment.JustifyMedium: case ParagraphAlignment.Distribute: case ParagraphAlignment.ThaiDistribute: paragraphStyle += "justify;"; break; case ParagraphAlignment.Center: paragraphStyle += "center;"; break; default: break; } } if (maskedParagraphProperties.lineSpacingType != ParagraphLineSpacingType.Single) { const lineSpacingInUI = this.unitConverter.twipsToUI(maskedParagraphProperties.lineSpacing) + unitTypeToString + ";"; paragraphStyle += "line-height: "; switch (maskedParagraphProperties.lineSpacingType) { case ParagraphLineSpacingType.AtLeast: paragraphStyle += lineSpacingInUI; break; case ParagraphLineSpacingType.Double: paragraphStyle += "2;"; break; case ParagraphLineSpacingType.Exactly: paragraphStyle += lineSpacingInUI + "mso-line-height-rule: exactly;"; break; case ParagraphLineSpacingType.Multiple: paragraphStyle += maskedParagraphProperties.lineSpacing + ";"; break; case ParagraphLineSpacingType.Sesquialteral: paragraphStyle += "1.5;"; break; default: break; } } if (ColorUtils.getAlpha(maskedParagraphProperties.shadingInfo.getActualColor(this.colorProvider)) > 0) paragraphStyle += "background: " + ColorHelper.getCssStringInternal(maskedParagraphProperties.shadingInfo.getActualColor(this.colorProvider)) + ";"; if (maskedParagraphProperties.leftIndent) paragraphStyle += "margin-left: " + this.unitConverter.twipsToUI(maskedParagraphProperties.leftIndent) + unitTypeToString + ";"; if (maskedParagraphProperties.rightIndent) paragraphStyle += "margin-right: " + this.unitConverter.twipsToUI(maskedParagraphProperties.rightIndent) + unitTypeToString + ";"; paragraphStyle += "margin-top: " + this.unitConverter.twipsToUI(maskedParagraphProperties.spacingBefore) + unitTypeToString + ";"; paragraphStyle += "margin-bottom: " + this.unitConverter.twipsToUI(maskedParagraphProperties.spacingAfter) + unitTypeToString + ";"; const topBorderStyle = this.getBorderCssString(maskedParagraphProperties.topBorder); if (topBorderStyle) paragraphStyle += "border-top:" + topBorderStyle + ";"; const leftBorderStyle = this.getBorderCssString(maskedParagraphProperties.leftBorder); if (leftBorderStyle) paragraphStyle += "border-left:" + leftBorderStyle + ";"; const bottomBorderStyle = this.getBorderCssString(maskedParagraphProperties.bottomBorder); if (bottomBorderStyle) paragraphStyle += "border-bottom:" + bottomBorderStyle + ";"; const rightBorderStyle = this.getBorderCssString(maskedParagraphProperties.rightBorder); if (rightBorderStyle) paragraphStyle += "border-right:" + rightBorderStyle + ";"; if (isRunInEmptyParagraph) { const charProps = run.getCharacterMergedProperties(); paragraphStyle += HtmlConverter.getCssRules(charProps, charProps.textColor.toRgb(this.colorProvider), false, false, false) .join(";"); } if (currentParagraph.isInList()) resultBuilder.startChild('li'); resultBuilder .startChild('p') .configure((e) => { if (paragraphStyle) e.style.cssText = paragraphStyle; if (isRunInEmptyParagraph) e.innerHTML = "&nbsp;"; }); } } } let html = new HtmlBuilder(); let innerHtml = new HtmlBuilder(); const length = Math.min(remainLength, iterator.currentInterval().length); switch (run.getType()) { case RunType.ParagraphRun: if (!isContinueMergingCell) { html.addCallback((builder) => builder.endChild('p')); if (run.paragraph.isInList()) { html.addCallback((builder) => builder.endChild('li')); html.addCallback((builder) => this.endList(model, builder, lists, iterator.currentInterval().end)); } let paragraphEndPosition = run.paragraph.getEndPosition(); if (tableCell) { let parentRow = tableCell.parentRow; let parentTable = parentRow.parentTable; if (tableCell.endParagrapPosition.value == paragraphEndPosition) html.addCallback((builder) => builder.endChild('td')); if (parentRow.getEndPosition() == paragraphEndPosition) { if (parentRow.gridAfter > 0) html.addCallback((builder) => { builder .addElement('td') .configure((el) => { el.style.cssText = "mso-cell-special:placeholder"; el.setAttribute('colspan', parentRow.gridAfter.toString()); el.innerHTML = "&nbsp;"; }) .endChild('td'); }); html.addCallback((builder) => { builder.endChild('tr'); }); } if (parentTable.getEndPosition() == paragraphEndPosition) html.addCallback((builder) => { builder .endChild('tbody') .endChild('table'); }); } } break; case RunType.InlinePictureRun: case RunType.AnchoredPictureRun: { const picRun = run; const charMergProps = run.getCharacterMergedProperties(); const pictureBox = new LayoutPictureBox(charMergProps, charMergProps.getLayoutColorInfo(this.colorProvider), picRun.cacheInfo, picRun.getActualSize().applyConverter(UnitConverter.twipsToPixels), picRun.info.nonVisualDrawingProperties.description); const { cacheInfo, hyperlinkTip, description } = pictureBox; innerHtml .clear() .addElement(this.documentRenderer.renderPictureBoxContent(pictureBox.createSize(), cacheInfo, hyperlinkTip, description)); break; } case RunType.InlineTextBoxRun: case RunType.AnchoredTextBoxRun: { let textBoxRun = run; let internalSubDocument = model.subDocuments[textBoxRun.subDocId]; innerHtml .clear() .startChild('table') .configure((el) => { el.setAttribute('border', '1'); el.style.cssText = 'border-width: 0px; border-collapse: collapse; border-spacing: 0px;'; el.setAttribute('id', guidLabel.replace("id=\"", "").replace("\"", "")); }) .startChild('tbody') .startChild('tr') .startChild('td') .configure((el) => { el.style.cssText = this.getTextBoxStyleString(textBoxRun); }) .assignFrom(this.getHtmlElementsByInterval(model, internalSubDocument, new FixedInterval(0, internalSubDocument.getDocumentEndPosition()), guidLabel)) .endChild('td') .endChild('tr') .endChild('tbody') .endChild('table'); break; } case RunType.FieldCodeStartRun: isInsideFieldCode = true; const fieldIndex = Field.normedBinaryIndexOf(subDocument.fields, currentPosition + 1); const field = subDocument.fields[fieldIndex]; if (field.isHyperlinkField()) { hyperlinkInfo = field.getHyperlinkInfo(); isInsideHyperlink = true; } fieldDeep++; break; case RunType.FieldCodeEndRun: isInsideFieldCode = false; break; case RunType.FieldResultEndRun: fieldDeep--; if (!fieldDeep) isInsideHyperlink = false; hasFields = true; break; case RunType.LayoutDependentRun: let currentField = subDocument.fields[Field.normedBinaryIndexOf(subDocument.fields, currentPosition)]; if (currentField) { let codeText = StringUtils.trim(subDocument.getText(currentField.getCodeInterval()).split("\\")[0]).toUpperCase(); if (codeText == "NUMPAGES" && isDefined(this.lastMaxNumPages)) innerHtml .clear() .addElement(this.lastMaxNumPages.toString()); else if (codeText == "PAGE" && isDefined(this.pageIndex)) innerHtml .clear() .addElement((this.pageIndex + 1).toString()); } break; default: if (!isInsideFieldCode) innerHtml = this.getHtmlText(subDocument.getText(new FixedInterval(currentPosition, length))); break; } if (hyperlinkInfo && !isInsideHyperlink) { const sanitaizeHyperlinkURIs = (_b = (_a = this.htmlExporterOptions) === null || _a === void 0 ? void 0 : _a.sanitaizeHyperlinkURIs) !== null && _b !== void 0 ? _b : false; const convertRelativeURIsToAbsolute = (_d = (_c = this.htmlExporterOptions) === null || _c === void 0 ? void 0 : _c.convertRelativeURIsToAbsolute) !== null && _d !== void 0 ? _d : false; let url = hyperlinkInfo.uri; const options = createUrlValidationOptions(this.exportModelOptions.modelManager); if (!sanitaizeHyperlinkURIs || UrlUtils.isValid(url, options)) { if (convertRelativeURIsToAbsolute && UrlUtils.isRelative(url)) url = UrlUtils.convertToAbsolute(url).href; if (hyperlinkInfo.anchor != "") url = url + "#" + hyperlinkInfo.anchor; } else url = UrlUtils.EmptyPage; const tooltip = hyperlinkInfo.tip; html .clear() .startChild('a') .configure((el) => { el.setAttribute('href', url); if (tooltip) el.setAttribute('title', tooltip); }) .assignFrom(hyperlinkInnerHtml) .endChild('a'); hyperlinkInfo = null; hyperlinkInnerHtml.clear(); } if (html.isEmpty() && !innerHtml.isEmpty()) { const characterProperties = run.getCharacterMergedProperties(); const boxStyle = HtmlConverter.getCssRules(characterProperties, characterProperties.textColor.toRgb(this.colorProvider), run.getType() == RunType.TextRun, false, false). join(";"); html .startChild('span') .configure((el) => { el.style.cssText = boxStyle; }) .assignFrom(innerHtml) .endChild('span'); if (hyperlinkInfo) { if (isInsideHyperlink) { hyperlinkInnerHtml.assignFrom(html); html.clear(); } } else { if (characterProperties.fontUnderlineType != UnderlineType.None && !characterProperties.underlineWordsOnly) { const underlineColor = characterProperties.underlineColor.toRgb(this.colorProvider); const cssColorValue = (underlineColor != ColorHelper.AUTOMATIC_COLOR) ? ColorHelper.getCssStringInternal(underlineColor) : "initial"; const builder = new HtmlBuilder(); builder .startChild('span') .configure((el) => { el.style.cssText = "text-decoration: underline; color: " + cssColorValue; }) .assignFrom(html) .endChild('span'); html = builder; } if (characterProperties.script !== CharacterFormattingScript.Normal) { const builder = new HtmlBuilder(); builder .startChild('span') .configure((el) => { el.style.cssText = "font-size: " + characterProperties.fontSize + "px;"; }) .assignFrom(html) .endChild('span'); html = builder; } if (ColorUtils.getAlpha(CharacterProperties.getActualBackgroundColor(characterProperties, this.colorProvider)) > 0) { const builder = new HtmlBuilder(); builder .startChild('span') .configure((el) => { el.style.cssText = "background: " + ColorHelper.getCssStringInternal(CharacterProperties.getActualBackgroundColor(characterProperties, this.colorProvider)); }) .assignFrom(html) .endChild('span'); html = builder; } } } resultBuilder.assignFrom(html); currentPosition += length; remainLength -= length; } if (/^<td[^>]*>/gi.test(resultBuilder.getHtmlString())) { const builder = new HtmlBuilder(); builder.startChild('tr'); builder.assignFrom(resultBuilder); resultBuilder = builder; } if (/<\/td>$/gi.test(resultBuilder.getHtmlString())) resultBuilder.endChild("tr"); if (/^<tr[^>]*>/gi.test(resultBuilder.getHtmlString())) { const builder = new HtmlBuilder(); builder .startChild('table') .configure((el) => { el.style.cssText = this.getTableStyle(model, null); }) .startChild('tbody') .assignFrom(resultBuilder); resultBuilder = builder; } if (/<\/tr>$/gi.test(resultBuilder.getHtmlString())) resultBuilder .endChild('tbody') .endChild('table'); if (hasFields && resultBuilder.isEmpty()) resultBuilder .startChild('span') .configure((el) => { el.classList.add('field-mark'); el.innerHTML = "&nbsp;"; }) .endChild('span'); return resultBuilder; } getParagraphsByInterval(subDocument, interval) { const paragraphsInInterval = subDocument.getParagraphsByInterval(interval); const paragraphs = []; for (let i = 0, paragraphInInterval; paragraphInInterval = paragraphsInInterval[i]; i++) { if (interval.containsWithIntervalEnd(paragraphInInterval.getEndPosition())) paragraphs.push(paragraphInInterval); } return paragraphs; } getListsByParagraphs(paragraphs) { const listsInInterval = []; let previousList = null; for (let i = 0, paragraph; paragraph = paragraphs[i]; i++) { if (paragraph.isInList()) { const numberingListIndex = paragraph.getNumberingListIndex(); const listLevelIndex = paragraph.getListLevelIndex(); const start = paragraph.startLogPosition.value; const end = paragraph.getEndPosition(); let list = ListUtils.reverseElementBy(listsInInterval, (list) => { return list.listLevelIndex <= (previousList === null || previousList === void 0 ? void 0 : previousList.listLevelIndex) && list.numberingListIndex === numberingListIndex && list.listLevelIndex === listLevelIndex; }); if (!list) { const parentList = (previousList === null || previousList === void 0 ? void 0 : previousList.numberingListIndex) === numberingListIndex ? previousList : null; list = { parentList, numberingListIndex, listLevelIndex, start, end }; listsInInterval.push(list); } previousList = list; do { list.end = end; } while (list = list.parentList); } } return listsInInterval; } addParentTableRecursively(model, builder, parentCell, paragraphStartPosition) { const parentRow = parentCell.parentRow; const parentTable = parentRow.parentTable; if (parentTable.parentCell) this.addParentTableRecursively(model, builder, parentTable.parentCell, paragraphStartPosition); if (parentTable.getStartPosition() === paragraphStartPosition) { builder .startChild('table') .configure(e => e.style.cssText = this.getTableStyle(model, parentTable)) .startChild('tbody'); } if (parentRow.getStartPosition() === paragraphStartPosition) { builder.startChild('tr'); if (parentRow.gridBefore > 0) { builder .startChild('td') .configure(el => { el.style.cssText = 'mso-cell-special:placeholder'; el.setAttribute('colspan', parentRow.gridBefore.toString()); el.innerHTML = '&nbsp;'; }) .endChild('td'); } } if (parentCell.startParagraphPosition.value === paragraphStartPosition) { builder .startChild('td') .configure((el) => { el.style.cssText = this.getCellStyle(model, parentCell); if (parentCell.columnSpan > 1) el.setAttribute('colspan', parentCell.columnSpan.toString()); }); } } startList(model, subDocument, interval, builder, lists, position) { if (!lists.length) return; let listIndex = lists.findIndex((list) => list.start === position); if (listIndex < 0 && position === interval.start) { const firstParagraph = subDocument.getParagraphByPosition(position); if (firstParagraph.getNumberingListIndex() === lists[0].numberingListIndex) listIndex = 0; } if (listIndex > -1) { const numberingList = model.numberingLists[lists[listIndex].numberingListIndex]; const numberingListFormat = numberingList.levels[lists[listIndex].listLevelIndex].getListLevelProperties().format; const numberingListType = numberingList.getListType(); let listFormatType = ""; switch (numberingListFormat) { case NumberingFormat.Bullet: listFormatType = "disc"; break; case NumberingFormat.Decimal: listFormatType = "decimal"; break; case NumberingFormat.LowerLetter: listFormatType = "lower-alpha"; break; case NumberingFormat.UpperLetter: listFormatType = "upper-alpha"; break; case NumberingFormat.LowerRoman: listFormatType = "lower-roman"; break; case NumberingFormat.UpperRoman: listFormatType = "upper-roman"; break; default: break; } builder .startChild(numberingListType !== NumberingType.Bullet ? "ol" : "ul") .configure((e) => e.style.cssText = "list-style-type:" + listFormatType); } } endList(model, builder, lists, endPosition) { for (let i = lists.length - 1; i >= 0; i--) { if (lists[i].end === endPosition) { const listType = model.numberingLists[lists[i].numberingListIndex].getListType(); lists.splice(i, 1); builder.endChild(listType != NumberingType.Bullet ? "ol" : "ul"); } } } getHtmlText(text) { const result = new HtmlBuilder(); for (let i = 0; i < text.length; i++) { const char = text.charAt(i); switch (char) { case RichUtils.specialCharacters.PageBreak: case RichUtils.specialCharacters.ColumnBreak: case RichUtils.specialCharacters.SectionMark: result.addCallback((builder) => builder.addBreak("break-before:always")); break; case RichUtils.specialCharacters.LineBreak: result.addCallback((builder) => builder.addBreak()); break; default: result.addCallback((builder) => { builder.configure((el) => el.innerHTML += EncodeUtils.encodeHtml(text.substring(i))); }); return result; } } return result; } getBorderCssString(borderInfo) { let borderStyle = ""; if (borderInfo) { if (borderInfo.width) borderStyle += " " + UnitConverter.twipsToPixels(borderInfo.width) + "px"; switch (borderInfo.style) { case BorderLineStyle.Dashed: borderStyle += " dashed"; break; case BorderLineStyle.Dotted: borderStyle += " dotted"; break; case BorderLineStyle.Double: borderStyle += " double"; break; case BorderLineStyle.Inset: borderStyle += " inset"; break; case BorderLineStyle.None: borderStyle += " none"; break; case BorderLineStyle.Outset: borderStyle += " outset"; break; case BorderLineStyle.Single: borderStyle += " solid"; default: break; } const rgba = this.colorProvider.getRgbaFromModelColor(borderInfo.color); if (ColorUtils.getAlpha(rgba) > 0) borderStyle += " " + ColorHelper.getCssStringInternal(rgba); } return borderStyle; } getTableWidthUnitCssString(width) { return width.type == TableWidthUnitType.FiftiethsOfPercent ? width.value / 50 + "%" : UnitConverter.twipsToPoints(width.value) + "pt"; } getTableStyle(model, table) { let defaultTableProperties = model.defaultTableProperties; let tableProperties = table ? table.properties : defaultTableProperties; let style = table ? table.style : model.getDefaultTableStyle(); let tableStyle = ""; let tableIndent = new TablePropertiesMergerIndent().getProperty(tableProperties, style, ConditionalTableStyleFormatting.WholeTable, defaultTableProperties); if (tableIndent.value) tableStyle += "margin-left:" + this.getTableWidthUnitCssString(tableIndent) + ";"; let cellSpacing = new TablePropertiesMergerCellSpacing().getProperty(tableProperties, style, ConditionalTableStyleFormatting.WholeTable, defaultTableProperties); tableStyle += (cellSpacing.value ? "border-spacing:" + this.getTableWidthUnitCssString(cellSpacing) : "border-collapse: collapse") + ";"; return tableStyle; } getCellStyle(model, cell) { let cellProperties = cell.properties; let defaultTableProperties = model.defaultTableProperties; let defaultCellProperties = model.defaultTableCellProperties; let parentTable = cell.parentRow.parentTable; let tableStyle = parentTable.style; let tableHorizontalBorderStyle = this.getBorderCssString((new TablePropertiesMergerBorderHorizontal()) .getProperty(parentTable.properties, tableStyle, ConditionalTableStyleFormatting.WholeTable, defaultTableProperties)); let tableVerticalBorderStyle = this.getBorderCssString((new TablePropertiesMergerBorderVertical()) .getProperty(parentTable.properties, tableStyle, ConditionalTableStyleFormatting.WholeTable, defaultTableProperties)); let cellStyle = ""; let topBorderStyle = this.getBorderCssString(cell.getActualTopCellBorder(defaultCellProperties)) || tableVerticalBorderStyle; if (topBorderStyle) cellStyle += "border-top:" + topBorderStyle + ";"; let leftBorderStyle = this.getBorderCssString(cell.getActualLeftCellBorder(defaultCellProperties)) || tableHorizontalBorderStyle; if (leftBorderStyle) cellStyle += "border-left:" + leftBorderStyle + ";"; let bottomBorderStyle = this.getBorderCssString(cell.getActualBottomCellBorder(defaultCellProperties)) || tableVerticalBorderStyle; if (bottomBorderStyle) cellStyle += "border-bottom:" + bottomBorderStyle + ";"; let rightBorderStyle = this.getBorderCssString(cell.getActualRightCellBorder(defaultCellProperties)) || tableHorizontalBorderStyle; if (rightBorderStyle) cellStyle += "border-right:" + rightBorderStyle + ";"; let marginLeft = cell.getActualLeftCellMargin(model); if (marginLeft.value) cellStyle += "padding-left:" + this.getTableWidthUnitCssString(marginLeft) + ";"; let marginTop = cell.getActualTopCellMargin(model); if (marginTop.value) cellStyle += "padding-top:" + this.getTableWidthUnitCssString(marginTop) + ";"; let marginRight = cell.getActualRightCellMargin(model); if (marginRight.value) cellStyle += "padding-right:" + this.getTableWidthUnitCssString(marginRight) + ";"; let marginBottom = cell.getActualBottomCellMargin(model); if (marginBottom.value) cellStyle += "padding-bottom:" + this.getTableWidthUnitCssString(marginBottom) + ";"; let verticalAlignment = new TableCellVerticalAlignmentMerger().getProperty(cellProperties, tableStyle, cell.conditionalFormatting, defaultCellProperties); switch (verticalAlignment) { case TableCellVerticalAlignment.Bottom: cellStyle += "vertical-align:bottom;"; break; case TableCellVerticalAlignment.Center: cellStyle += "vertical-align:middle;"; break; case TableCellVerticalAlignment.Top: cellStyle += "vertical-align:top;"; break; default: break; } let cellBackground = new TableCellPropertiesMergerShadingInfo().getProperty(cellProperties, tableStyle, cell.conditionalFormatting, defaultCellProperties) .getActualColor(this.colorProvider); if (ColorUtils.getAlpha(cellBackground) > 0) cellStyle += "background: " + ColorHelper.getCssStringInternal(cellBackground) + ";"; cellStyle += "width: " + UnitConverter.twipsToPixels(cell.preferredWidth.value) + "px;"; return cellStyle; } getTextBoxStyleString(textBoxRun) { let contentMargins = textBoxRun.textBoxProperties.getContentMargins(); let result = "padding-top:" + UnitConverter.twipsToPixels(contentMargins.top) + "px;"; result += "padding-bottom:" + UnitConverter.twipsToPixels(contentMargins.bottom) + "px;"; result += "padding-left:" + UnitConverter.twipsToPixels(contentMargins.left) + "px;"; result += "padding-right:" + UnitConverter.twipsToPixels(contentMargins.right) + "px;"; result += "border:" + UnitConverter.twipsToPixels(textBoxRun.shape.outlineWidth) + "px solid " + ColorHelper.getCssString(textBoxRun.shape.outlineColor, true) + ";"; result += "background-color:" + ColorHelper.getCssString(textBoxRun.shape.fillColor, true) + ";"; return result; } }