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 += `${isList.split(' ')[0]}>`
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.split(' ')[0]}>`
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, ' ')}`
}