import { getHorizontalAlign } from './align' import { getTextByPathList } from './utils' import { getFontType, getFontColor, getFontSize, getFontBold, getFontItalic, getFontDecoration, getFontDecorationLine, getFontSpace, getFontSubscript, getFontShadow } from './fontStyle' export function genTextBody( textBodyNode, spNode, slideLayoutSpNode, type, warpObj ) { if (!textBodyNode) return '' let text = '' const listCounters = {} // 添加列表计数器对象 const slideMasterTextStyles = warpObj['slideMasterTextStyles'] const pFontStyle = getTextByPathList(spNode, ['p:style', 'a:fontRef']) const pNode = textBodyNode['a:p'] const pNodes = pNode.constructor === Array ? pNode : [pNode] let isList = '' for (const pNode of pNodes) { let rNode = pNode['a:r'] let fldNode = pNode['a:fld'] let brNode = pNode['a:br'] if (rNode) { rNode = rNode.constructor === Array ? rNode : [rNode] if (fldNode) { fldNode = fldNode.constructor === Array ? fldNode : [fldNode] rNode = rNode.concat(fldNode) } if (brNode) { brNode = brNode.constructor === Array ? brNode : [brNode] brNode.forEach((item) => (item.type = 'br')) if (brNode.length > 1) brNode.shift() rNode = rNode.concat(brNode) rNode.sort((a, b) => { if (!a.attrs || !b.attrs) return true return a.attrs.order - b.attrs.order }) } } const align = getHorizontalAlign(pNode, spNode, type, warpObj) const listType = getListType(pNode) if (listType) { const [tagName, className] = listType.split(' ') const level = parseInt(pNode['a:pPr'].attrs?.lvl || '0') // 获取列表层级 const indentSize = (level + 1) * 20 // 根据层级计算缩进大小 if (!isList) { text += `<${tagName} style="list-style: none; " class="${className}">` isList = listType listCounters[className] = 0 } else if (isList && isList !== listType) { text += `` text += `<${tagName} style="list-style: none; " class="${className}">` isList = listType listCounters[className] = 0 } listCounters[className]++ const currentNumber = listCounters[className] text += `
  • ` if (className === 'custom-bullet') { const bulletChar = pNode['a:pPr']['a:buChar'].attrs?.char || '•' const symbolMap = { 'n': '■', // 实心方块 'l': '●', // 实心圆 'u': '◆', // 实心菱形 'p': '□', // 空心方块 'ü': '✔', // 对号 'Ø': '➢', // 箭头 '': '•' // 默认圆点 } const displayChar = symbolMap[bulletChar] || bulletChar // 获取字体大小,与内容保持一致 const fontSize = getFontSize(textBodyNode, slideLayoutSpNode, type, slideMasterTextStyles) const fontSizeStyle = fontSize ? `font-size: ${fontSize};` : '' text += `${displayChar}` } else { let displayNumber = '' switch (className) { case 'circle-number': const circleNums = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'] displayNumber = circleNums[currentNumber - 1] || `${currentNumber}` break case 'roman-upper': const romanNums = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X'] displayNumber = `${romanNums[currentNumber - 1]}.` break case 'alpha-upper': displayNumber = `${String.fromCharCode(64 + currentNumber)}.` break case 'alpha-lower-paren': displayNumber = `${String.fromCharCode(96 + currentNumber)})` break case 'alpha-lower': displayNumber = `${String.fromCharCode(96 + currentNumber)}.` break case 'chinese-upper': // 添加中文数字 const chineseUpperNums = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'] displayNumber = `${chineseUpperNums[currentNumber - 1]}.` break default: displayNumber = `${currentNumber}.` } // 获取字体大小,与内容保持一致 const fontSize = getFontSize(textBodyNode, slideLayoutSpNode, type, slideMasterTextStyles) const fontSizeStyle = fontSize ? `font-size: ${fontSize};` : '' text += `${displayNumber}` } } else { if (isList) { text += `` isList = '' } text += `

    ` } if (!rNode) { text += genSpanElement( pNode, spNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj ) } else { for (const rNodeItem of rNode) { text += genSpanElement( rNodeItem, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj ) } } if (listType) text += '

  • ' else text += '

    ' } return text } export function getListType(node) { const pPrNode = node['a:pPr'] if (!pPrNode) return '' if (pPrNode['a:buChar']) { return 'ul custom-bullet' } if (pPrNode['a:buAutoNum']) { const numType = pPrNode['a:buAutoNum'].attrs?.type || 'arabicPeriod' // 根据不同的编号类型返回对应的样式 switch (numType) { case 'circleNumDbPlain': return 'ol circle-number' // ①②③ case 'romanUcPeriod': return 'ol roman-upper' // I. II. III. case 'alphaUcPeriod': return 'ol alpha-upper' // A. B. C. case 'alphaLcParen': return 'ol alpha-lower-paren' // a) b) c) case 'alphaLcPeriod': return 'ol alpha-lower' // a. b. c. case 'ea1JpnChsDbPeriod': return 'ol chinese-upper' // 一. 二. 三. default: return 'ol decimal' // 1. 2. 3. } } return '' } export function genSpanElement( node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, type, warpObj ) { const lstStyle = textBodyNode['a:lstStyle'] const slideMasterTextStyles = warpObj['slideMasterTextStyles'] let lvl = 1 const pPrNode = pNode['a:pPr'] if (pPrNode) { const lvlNode = getTextByPathList(pPrNode, ['attrs', 'lvl']) if (lvlNode !== undefined) lvl = parseInt(lvlNode) + 1 } let fontSize const directSize = getTextByPathList(node, ['a:rPr', 'attrs', 'sz']) if (directSize) { // 如果节点本身有字体大小设置,直接使用 fontSize = getFontSize(node, slideLayoutSpNode, type, slideMasterTextStyles) } else { // 如果节点没有字体大小设置,使用 textBodyNode fontSize = getFontSize(textBodyNode, slideLayoutSpNode, type, slideMasterTextStyles) } let text = node['a:t'] if (typeof text !== 'string') text = getTextByPathList(node, ['a:fld', 'a:t']) if (typeof text !== 'string') text = ' ' let styleText = '' const fontColor = getFontColor( node, pNode, lstStyle, pFontStyle, lvl, warpObj ) const fontType = getFontType(node, type, warpObj) const fontBold = getFontBold(node) const fontItalic = getFontItalic(node) const fontDecoration = getFontDecoration(node) const fontDecorationLine = getFontDecorationLine(node) const fontSpace = getFontSpace(node) const shadow = getFontShadow(node, warpObj) const subscript = getFontSubscript(node) if (fontColor) styleText += `color: ${fontColor};` if (fontSize) styleText += `font-size: ${fontSize};` if (fontType) styleText += `font-family: ${fontType};` if (fontBold) styleText += `font-weight: ${fontBold};` if (fontItalic) styleText += `font-style: ${fontItalic};` if (fontDecoration) styleText += `text-decoration: ${fontDecoration};` if (fontDecorationLine) { styleText += `text-decoration-line: ${fontDecorationLine};` } if (fontSpace) styleText += `letter-spacing: ${fontSpace};` if (subscript) styleText += `vertical-align: ${subscript};` if (shadow) styleText += `text-shadow: ${shadow};` const linkID = getTextByPathList(node, [ 'a:rPr', 'a:hlinkClick', 'attrs', 'r:id' ]) if (linkID) { const linkURL = warpObj['slideResObj'][linkID]['target'] return `${text .replace(/\t/g, '    ') .replace(/\s/g, ' ')}` } return `${text .replace(/\t/g, '    ') .replace(/\s/g, ' ')}` }