| |
| |
| |
|
|
| import { |
| BARCHART_COLORS, |
| CHART_NAME, |
| CHART_TYPE, |
| DEF_CELL_BORDER, |
| DEF_CELL_MARGIN_IN, |
| DEF_CHART_BORDER, |
| DEF_FONT_COLOR, |
| DEF_FONT_SIZE, |
| DEF_SHAPE_LINE_COLOR, |
| DEF_SLIDE_MARGIN_IN, |
| EMU, |
| IMG_PLAYBTN, |
| MASTER_OBJECTS, |
| PIECHART_COLORS, |
| SCHEME_COLOR_NAMES, |
| SHAPE_NAME, |
| SHAPE_TYPE, |
| SLIDE_OBJECT_TYPES, |
| TEXT_HALIGN, |
| TEXT_VALIGN, |
| } from './core-enums' |
| import { |
| AddSlideProps, |
| BackgroundProps, |
| FormulaProps, |
| IChartMulti, |
| IChartOptsLib, |
| IOptsChartData, |
| ISlideObject, |
| ImageProps, |
| MediaProps, |
| ObjectOptions, |
| OptsChartGridLine, |
| PresLayout, |
| PresSlide, |
| ShapeLineProps, |
| ShapeProps, |
| SlideLayout, |
| SlideMasterProps, |
| TableCell, |
| TableProps, |
| TableRow, |
| TextProps, |
| TextPropsOptions, |
| } from './core-interfaces' |
| import { getSlidesForTableRows } from './gen-tables' |
| import { encodeXmlEntities, getNewRelId, getSmartParseNumber, inch2Emu, valToPts, correctShadowOptions } from './gen-utils' |
|
|
| |
| let _chartCounter = 0 |
|
|
| |
| |
| |
| |
| |
| export function createSlideMaster(props: SlideMasterProps, target: SlideLayout): void { |
| |
| |
| if (props.bkgd) target.bkgd = props.bkgd |
|
|
| |
| if (props.objects && Array.isArray(props.objects) && props.objects.length > 0) { |
| props.objects.forEach((object, idx) => { |
| const key = Object.keys(object)[0] |
| const tgt = target as PresSlide |
| if (MASTER_OBJECTS[key] && key === 'chart') addChartDefinition(tgt, object[key].type, object[key].data, object[key].opts) |
| else if (MASTER_OBJECTS[key] && key === 'image') addImageDefinition(tgt, object[key]) |
| else if (MASTER_OBJECTS[key] && key === 'line') addShapeDefinition(tgt, SHAPE_TYPE.LINE, object[key]) |
| else if (MASTER_OBJECTS[key] && key === 'rect') addShapeDefinition(tgt, SHAPE_TYPE.RECTANGLE, object[key]) |
| else if (MASTER_OBJECTS[key] && key === 'text') addTextDefinition(tgt, [{ text: object[key].text }], object[key].options, false) |
| else if (MASTER_OBJECTS[key] && key === 'placeholder') { |
| |
| object[key].options.placeholder = object[key].options.name |
| delete object[key].options.name |
| object[key].options._placeholderType = object[key].options.type |
| delete object[key].options.type |
| object[key].options._placeholderIdx = 100 + idx |
| addTextDefinition(tgt, [{ text: object[key].text }], object[key].options, true) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| }) |
| } |
|
|
| |
| if (props.slideNumber && typeof props.slideNumber === 'object') target._slideNumberProps = props.slideNumber |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function addChartDefinition(target: PresSlide, type: CHART_NAME | IChartMulti[], data: IOptsChartData[], opt: IChartOptsLib): object { |
| function correctGridLineOptions(glOpts: OptsChartGridLine): void { |
| if (!glOpts || glOpts.style === 'none') return |
| if (glOpts.size !== undefined && (isNaN(Number(glOpts.size)) || glOpts.size <= 0)) { |
| console.warn('Warning: chart.gridLine.size must be greater than 0.') |
| delete glOpts.size |
| } |
| if (glOpts.style && !['solid', 'dash', 'dot'].includes(glOpts.style)) { |
| console.warn('Warning: chart.gridLine.style options: `solid`, `dash`, `dot`.') |
| delete glOpts.style |
| } |
| if (glOpts.cap && !['flat', 'square', 'round'].includes(glOpts.cap)) { |
| console.warn('Warning: chart.gridLine.cap options: `flat`, `square`, `round`.') |
| delete glOpts.cap |
| } |
| } |
|
|
| const chartId = ++_chartCounter |
| const resultObject = { |
| _type: null, |
| text: null, |
| options: null, |
| chartRid: null, |
| } |
| |
| |
| |
| let tmpOpt = null |
| let tmpData = [] |
| if (Array.isArray(type)) { |
| |
| |
| |
| |
| type.forEach(obj => { |
| tmpData = tmpData.concat(obj.data) |
| }) |
| tmpOpt = data || opt |
| } else { |
| tmpData = data |
| tmpOpt = opt |
| } |
| tmpData.forEach((item, i) => { |
| item._dataIndex = i |
|
|
| |
| if (item.labels !== undefined && !Array.isArray(item.labels[0])) { |
| item.labels = [item.labels as string[]] |
| } |
| }) |
| const options: IChartOptsLib = tmpOpt && typeof tmpOpt === 'object' ? tmpOpt : {} |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| options._type = type |
| options.x = typeof options.x !== 'undefined' && options.x != null && !isNaN(Number(options.x)) ? options.x : 1 |
| options.y = typeof options.y !== 'undefined' && options.y != null && !isNaN(Number(options.y)) ? options.y : 1 |
| options.w = options.w || '50%' |
| options.h = options.h || '50%' |
| options.objectName = options.objectName |
| ? encodeXmlEntities(options.objectName) |
| : `Chart ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.chart).length}` |
|
|
| |
| if (!['bar', 'col'].includes(options.barDir || '')) options.barDir = 'col' |
|
|
| |
| |
| if (options._type === CHART_TYPE.AREA) { |
| if (!['stacked', 'standard', 'percentStacked'].includes(options.barGrouping || '')) options.barGrouping = 'standard' |
| } |
| if (options._type === CHART_TYPE.BAR) { |
| if (!['clustered', 'stacked', 'percentStacked'].includes(options.barGrouping || '')) options.barGrouping = 'clustered' |
| } |
| if (options._type === CHART_TYPE.BAR3D) { |
| if (!['clustered', 'stacked', 'standard', 'percentStacked'].includes(options.barGrouping || '')) options.barGrouping = 'standard' |
| } |
| if (options.barGrouping?.includes('tacked')) { |
| if (!options.barGapWidthPct) options.barGapWidthPct = 50 |
| } |
| |
| |
| if (options.dataLabelPosition) { |
| if (options._type === CHART_TYPE.AREA || options._type === CHART_TYPE.BAR3D || options._type === CHART_TYPE.DOUGHNUT || options._type === CHART_TYPE.RADAR) { delete options.dataLabelPosition } |
| if (options._type === CHART_TYPE.PIE) { |
| if (!['bestFit', 'ctr', 'inEnd', 'outEnd'].includes(options.dataLabelPosition)) delete options.dataLabelPosition |
| } |
| if (options._type === CHART_TYPE.BUBBLE || options._type === CHART_TYPE.BUBBLE3D || options._type === CHART_TYPE.LINE || options._type === CHART_TYPE.SCATTER) { |
| if (!['b', 'ctr', 'l', 'r', 't'].includes(options.dataLabelPosition)) delete options.dataLabelPosition |
| } |
| if (options._type === CHART_TYPE.BAR) { |
| if (!['stacked', 'percentStacked'].includes(options.barGrouping || '')) { |
| if (!['ctr', 'inBase', 'inEnd'].includes(options.dataLabelPosition)) delete options.dataLabelPosition |
| } |
| if (!['clustered'].includes(options.barGrouping || '')) { |
| if (!['ctr', 'inBase', 'inEnd', 'outEnd'].includes(options.dataLabelPosition)) delete options.dataLabelPosition |
| } |
| } |
| } |
| options.dataLabelBkgrdColors = options.dataLabelBkgrdColors || !options.dataLabelBkgrdColors ? options.dataLabelBkgrdColors : false |
| if (!['b', 'l', 'r', 't', 'tr'].includes(options.legendPos || '')) options.legendPos = 'r' |
|
|
| |
| if (!['cone', 'coneToMax', 'box', 'cylinder', 'pyramid', 'pyramidToMax'].includes(options.bar3DShape || '')) options.bar3DShape = 'box' |
| |
| |
| if (!['circle', 'dash', 'diamond', 'dot', 'none', 'square', 'triangle'].includes(options.lineDataSymbol || '')) options.lineDataSymbol = 'circle' |
| if (!['gap', 'span'].includes(options.displayBlanksAs || '')) options.displayBlanksAs = 'span' |
| if (!['standard', 'marker', 'filled'].includes(options.radarStyle || '')) options.radarStyle = 'standard' |
| options.lineDataSymbolSize = options.lineDataSymbolSize && !isNaN(options.lineDataSymbolSize) ? options.lineDataSymbolSize : 6 |
| options.lineDataSymbolLineSize = options.lineDataSymbolLineSize && !isNaN(options.lineDataSymbolLineSize) ? valToPts(options.lineDataSymbolLineSize) : valToPts(0.75) |
| |
| if (options.layout) { |
| ['x', 'y', 'w', 'h'].forEach(key => { |
| const val = options.layout[key] |
| if (isNaN(Number(val)) || val < 0 || val > 1) { |
| console.warn('Warning: chart.layout.' + key + ' can only be 0-1') |
| delete options.layout[key] |
| } |
| }) |
| } |
|
|
| |
| options.catGridLine = options.catGridLine || (options._type === CHART_TYPE.SCATTER ? { color: 'D9D9D9', size: 1 } : { style: 'none' }) |
| options.valGridLine = options.valGridLine || (options._type === CHART_TYPE.SCATTER ? { color: 'D9D9D9', size: 1 } : {}) |
| options.serGridLine = options.serGridLine || (options._type === CHART_TYPE.SCATTER ? { color: 'D9D9D9', size: 1 } : { style: 'none' }) |
| correctGridLineOptions(options.catGridLine) |
| correctGridLineOptions(options.valGridLine) |
| correctGridLineOptions(options.serGridLine) |
| correctShadowOptions(options.shadow) |
|
|
| |
| options.showDataTable = options.showDataTable || !options.showDataTable ? options.showDataTable : false |
| options.showDataTableHorzBorder = options.showDataTableHorzBorder || !options.showDataTableHorzBorder ? options.showDataTableHorzBorder : true |
| options.showDataTableVertBorder = options.showDataTableVertBorder || !options.showDataTableVertBorder ? options.showDataTableVertBorder : true |
| options.showDataTableOutline = options.showDataTableOutline || !options.showDataTableOutline ? options.showDataTableOutline : true |
| options.showDataTableKeys = options.showDataTableKeys || !options.showDataTableKeys ? options.showDataTableKeys : true |
| options.showLabel = options.showLabel || !options.showLabel ? options.showLabel : false |
| options.showLegend = options.showLegend || !options.showLegend ? options.showLegend : false |
| options.showPercent = options.showPercent || !options.showPercent ? options.showPercent : true |
| options.showTitle = options.showTitle || !options.showTitle ? options.showTitle : false |
| options.showValue = options.showValue || !options.showValue ? options.showValue : false |
| options.showLeaderLines = options.showLeaderLines || !options.showLeaderLines ? options.showLeaderLines : false |
| options.catAxisLineShow = typeof options.catAxisLineShow !== 'undefined' ? options.catAxisLineShow : true |
| options.valAxisLineShow = typeof options.valAxisLineShow !== 'undefined' ? options.valAxisLineShow : true |
| options.serAxisLineShow = typeof options.serAxisLineShow !== 'undefined' ? options.serAxisLineShow : true |
|
|
| options.v3DRotX = !isNaN(options.v3DRotX) && options.v3DRotX >= -90 && options.v3DRotX <= 90 ? options.v3DRotX : 30 |
| options.v3DRotY = !isNaN(options.v3DRotY) && options.v3DRotY >= 0 && options.v3DRotY <= 360 ? options.v3DRotY : 30 |
| options.v3DRAngAx = options.v3DRAngAx || !options.v3DRAngAx ? options.v3DRAngAx : true |
| options.v3DPerspective = !isNaN(options.v3DPerspective) && options.v3DPerspective >= 0 && options.v3DPerspective <= 240 ? options.v3DPerspective : 30 |
|
|
| |
| options.barGapWidthPct = !isNaN(options.barGapWidthPct) && options.barGapWidthPct >= 0 && options.barGapWidthPct <= 1000 ? options.barGapWidthPct : 150 |
| options.barGapDepthPct = !isNaN(options.barGapDepthPct) && options.barGapDepthPct >= 0 && options.barGapDepthPct <= 1000 ? options.barGapDepthPct : 150 |
|
|
| options.chartColors = Array.isArray(options.chartColors) |
| ? options.chartColors |
| : options._type === CHART_TYPE.PIE || options._type === CHART_TYPE.DOUGHNUT |
| ? PIECHART_COLORS |
| : BARCHART_COLORS |
| options.chartColorsOpacity = options.chartColorsOpacity && !isNaN(options.chartColorsOpacity) ? options.chartColorsOpacity : null |
| |
| options.border = options.border && typeof options.border === 'object' ? options.border : null |
| if (options.border && (!options.border.pt || isNaN(options.border.pt))) options.border.pt = DEF_CHART_BORDER.pt |
| if (options.border && (!options.border.color || typeof options.border.color !== 'string')) options.border.color = DEF_CHART_BORDER.color |
| |
| options.plotArea = options.plotArea || {} |
| options.plotArea.border = options.plotArea.border && typeof options.plotArea.border === 'object' ? options.plotArea.border : null |
| if (options.plotArea.border && (!options.plotArea.border.pt || isNaN(options.plotArea.border.pt))) options.plotArea.border.pt = DEF_CHART_BORDER.pt |
| if (options.plotArea.border && (!options.plotArea.border.color || typeof options.plotArea.border.color !== 'string')) { options.plotArea.border.color = DEF_CHART_BORDER.color } |
| if (options.border) options.plotArea.border = options.border |
| options.plotArea.fill = options.plotArea.fill || { color: null, transparency: null } |
| if (options.fill) options.plotArea.fill.color = options.fill |
| |
| options.chartArea = options.chartArea || {} |
| options.chartArea.border = options.chartArea.border && typeof options.chartArea.border === 'object' ? options.chartArea.border : null |
| if (options.chartArea.border) { |
| options.chartArea.border = { |
| color: options.chartArea.border.color || DEF_CHART_BORDER.color, |
| pt: options.chartArea.border.pt || DEF_CHART_BORDER.pt, |
| } |
| } |
| options.chartArea.roundedCorners = typeof options.chartArea.roundedCorners === 'boolean' ? options.chartArea.roundedCorners : true |
| |
| options.dataBorder = options.dataBorder && typeof options.dataBorder === 'object' ? options.dataBorder : null |
| if (options.dataBorder && (!options.dataBorder.pt || isNaN(options.dataBorder.pt))) options.dataBorder.pt = 0.75 |
| if (options.dataBorder && options.dataBorder.color) { |
| const isHexColor = typeof options.dataBorder.color === 'string' && options.dataBorder.color.length === 6 && /^[0-9A-Fa-f]{6}$/.test(options.dataBorder.color) |
| const isSchemeColor = Object.values(SCHEME_COLOR_NAMES).includes(options.dataBorder.color as SCHEME_COLOR_NAMES) |
| if (!isHexColor && !isSchemeColor) { |
| options.dataBorder.color = 'F9F9F9' |
| } |
| } |
| |
| if (!options.dataLabelFormatCode && options._type === CHART_TYPE.SCATTER) options.dataLabelFormatCode = 'General' |
| if (!options.dataLabelFormatCode && (options._type === CHART_TYPE.PIE || options._type === CHART_TYPE.DOUGHNUT)) { options.dataLabelFormatCode = options.showPercent ? '0%' : 'General' } |
| options.dataLabelFormatCode = options.dataLabelFormatCode && typeof options.dataLabelFormatCode === 'string' ? options.dataLabelFormatCode : '#,##0' |
| |
| |
| if (!options.dataLabelFormatScatter && options._type === CHART_TYPE.SCATTER) options.dataLabelFormatScatter = 'custom' |
| |
| options.lineSize = typeof options.lineSize === 'number' ? options.lineSize : 2 |
| options.valAxisMajorUnit = typeof options.valAxisMajorUnit === 'number' ? options.valAxisMajorUnit : null |
|
|
| if (options._type === CHART_TYPE.AREA || options._type === CHART_TYPE.BAR || options._type === CHART_TYPE.BAR3D || options._type === CHART_TYPE.LINE) { |
| options.catAxisMultiLevelLabels = !!options.catAxisMultiLevelLabels |
| } else { |
| delete options.catAxisMultiLevelLabels |
| } |
|
|
| |
| resultObject._type = 'chart' |
| resultObject.options = options |
| resultObject.chartRid = getNewRelId(target) |
|
|
| |
| target._relsChart.push({ |
| rId: getNewRelId(target), |
| data: tmpData, |
| opts: options, |
| type: options._type, |
| globalId: chartId, |
| fileName: `chart${chartId}.xml`, |
| Target: `/ppt/charts/chart${chartId}.xml`, |
| }) |
|
|
| target._slideObjects.push(resultObject) |
| return resultObject |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function addImageDefinition(target: PresSlide, opt: ImageProps): void { |
| const newObject: ISlideObject = { |
| _type: null, |
| text: null, |
| options: null, |
| image: null, |
| imageRid: null, |
| hyperlink: null, |
| } |
| |
| const intPosX = opt.x || 0 |
| const intPosY = opt.y || 0 |
| const intWidth = opt.w || 0 |
| const intHeight = opt.h || 0 |
| const sizing = opt.sizing || null |
| const objHyperlink = opt.hyperlink || '' |
| const strImageData = opt.data || '' |
| const strImagePath = opt.path || '' |
| let imageRelId = getNewRelId(target) |
| const objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : `Image ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.image).length}` |
|
|
| |
| if (!strImagePath && !strImageData) { |
| console.error('ERROR: addImage() requires either \'data\' or \'path\' parameter!') |
| return null |
| } else if (strImagePath && typeof strImagePath !== 'string') { |
| console.error(`ERROR: addImage() 'path' should be a string, ex: {path:'/img/sample.png'} - you sent ${String(strImagePath)}`) |
| return null |
| } else if (strImageData && typeof strImageData !== 'string') { |
| console.error(`ERROR: addImage() 'data' should be a string, ex: {data:'image/png;base64,NMP[...]'} - you sent ${String(strImageData)}`) |
| return null |
| } else if (strImageData && typeof strImageData === 'string' && !strImageData.toLowerCase().includes('base64,')) { |
| console.error('ERROR: Image `data` value lacks a base64 header! Ex: \'image/png;base64,NMP[...]\')') |
| return null |
| } |
|
|
| |
| |
| let strImgExtn = ( |
| strImagePath |
| .substring(strImagePath.lastIndexOf('/') + 1) |
| .split('?')[0] |
| .split('.') |
| .pop() |
| .split('#')[0] || 'png' |
| ).toLowerCase() |
|
|
| |
| if (strImageData && /image\/(\w+);/.exec(strImageData) && /image\/(\w+);/.exec(strImageData).length > 0) { |
| strImgExtn = /image\/(\w+);/.exec(strImageData)[1] |
| } else if (strImageData?.toLowerCase().includes('image/svg+xml')) { |
| strImgExtn = 'svg' |
| } |
|
|
| |
| newObject._type = SLIDE_OBJECT_TYPES.image |
| newObject.image = strImagePath || 'preencoded.png' |
|
|
| |
| |
| |
| |
| newObject.options = { |
| x: intPosX || 0, |
| y: intPosY || 0, |
| w: intWidth || 1, |
| h: intHeight || 1, |
| altText: opt.altText || '', |
| rounding: typeof opt.rounding === 'boolean' ? opt.rounding : false, |
| sizing, |
| placeholder: opt.placeholder, |
| rotate: opt.rotate || 0, |
| flipV: opt.flipV || false, |
| flipH: opt.flipH || false, |
| transparency: opt.transparency || 0, |
| objectName, |
| shadow: correctShadowOptions(opt.shadow), |
| } |
|
|
| |
| if (strImgExtn === 'svg') { |
| |
| |
| |
| target._relsMedia.push({ |
| path: strImagePath || strImageData + 'png', |
| type: 'image/png', |
| extn: 'png', |
| data: strImageData || '', |
| rId: imageRelId, |
| Target: `../media/image-${target._slideNum}-${target._relsMedia.length + 1}.png`, |
| isSvgPng: true, |
| svgSize: { w: getSmartParseNumber(newObject.options.w, 'X', target._presLayout), h: getSmartParseNumber(newObject.options.h, 'Y', target._presLayout) }, |
| }) |
| newObject.imageRid = imageRelId |
| target._relsMedia.push({ |
| path: strImagePath || strImageData, |
| type: 'image/svg+xml', |
| extn: strImgExtn, |
| data: strImageData || '', |
| rId: imageRelId + 1, |
| Target: `../media/image-${target._slideNum}-${target._relsMedia.length + 1}.${strImgExtn}`, |
| }) |
| newObject.imageRid = imageRelId + 1 |
| } else { |
| |
| const dupeItem = target._relsMedia.filter(item => item.path && item.path === strImagePath && item.type === 'image/' + strImgExtn && !item.isDuplicate)[0] |
|
|
| target._relsMedia.push({ |
| path: strImagePath || 'preencoded.' + strImgExtn, |
| type: 'image/' + strImgExtn, |
| extn: strImgExtn, |
| data: strImageData || '', |
| rId: imageRelId, |
| isDuplicate: !!(dupeItem?.Target), |
| Target: dupeItem?.Target ? dupeItem.Target : `../media/image-${target._slideNum}-${target._relsMedia.length + 1}.${strImgExtn}`, |
| }) |
| newObject.imageRid = imageRelId |
| } |
|
|
| |
| if (typeof objHyperlink === 'object') { |
| if (!objHyperlink.url && !objHyperlink.slide) throw new Error('ERROR: `hyperlink` option requires either: `url` or `slide`') |
| else { |
| imageRelId++ |
|
|
| target._rels.push({ |
| type: SLIDE_OBJECT_TYPES.hyperlink, |
| data: objHyperlink.slide ? 'slide' : 'dummy', |
| rId: imageRelId, |
| Target: objHyperlink.url || objHyperlink.slide.toString(), |
| }) |
|
|
| objHyperlink._rId = imageRelId |
| newObject.hyperlink = objHyperlink |
| } |
| } |
|
|
| |
| target._slideObjects.push(newObject) |
| } |
|
|
| |
| |
| |
| |
| |
| export function addMediaDefinition(target: PresSlide, opt: MediaProps): void { |
| const intPosX = opt.x || 0 |
| const intPosY = opt.y || 0 |
| const intSizeX = opt.w || 2 |
| const intSizeY = opt.h || 2 |
| const strData = opt.data || '' |
| const strLink = opt.link || '' |
| const strPath = opt.path || '' |
| const strType = opt.type || 'audio' |
| let strExtn = '' |
| const strCover = opt.cover || IMG_PLAYBTN |
| const objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : `Media ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.media).length}` |
| const slideData: ISlideObject = { _type: SLIDE_OBJECT_TYPES.media } |
|
|
| |
| if (!strPath && !strData && strType !== 'online') { |
| throw new Error('addMedia() error: either `data` or `path` are required!') |
| } else if (strData && !strData.toLowerCase().includes('base64,')) { |
| throw new Error('addMedia() error: `data` value lacks a base64 header! Ex: \'video/mpeg;base64,NMP[...]\')') |
| } else if (strCover && !strCover.toLowerCase().includes('base64,')) { |
| throw new Error('addMedia() error: `cover` value lacks a base64 header! Ex: \'data:image/png;base64,iV[...]\')') |
| } |
| |
| if (strType === 'online' && !strLink) { |
| throw new Error('addMedia() error: online videos require `link` value') |
| } |
|
|
| |
| |
| strExtn = opt.extn || (strData ? strData.split(';')[0].split('/')[1] : strPath.split('.').pop()) || 'mp3' |
|
|
| |
| slideData.mtype = strType |
| slideData.media = strPath || 'preencoded.mov' |
| slideData.options = {} |
|
|
| |
| slideData.options.x = intPosX |
| slideData.options.y = intPosY |
| slideData.options.w = intSizeX |
| slideData.options.h = intSizeY |
| slideData.options.objectName = objectName |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if (strType === 'online') { |
| const relId1 = getNewRelId(target) |
| |
| target._relsMedia.push({ |
| path: strPath || 'preencoded' + strExtn, |
| data: 'dummy', |
| type: 'online', |
| extn: strExtn, |
| rId: relId1, |
| Target: strLink, |
| }) |
| slideData.mediaRid = relId1 |
|
|
| |
| target._relsMedia.push({ |
| path: 'preencoded.png', |
| data: strCover, |
| type: 'image/png', |
| extn: 'png', |
| rId: getNewRelId(target), |
| Target: `../media/image-${target._slideNum}-${target._relsMedia.length + 1}.png`, |
| }) |
| } else { |
| |
| const dupeItem = target._relsMedia.filter(item => item.path && item.path === strPath && item.type === strType + '/' + strExtn && !item.isDuplicate)[0] |
|
|
| |
| const relId1 = getNewRelId(target) |
| target._relsMedia.push({ |
| path: strPath || 'preencoded' + strExtn, |
| type: strType + '/' + strExtn, |
| extn: strExtn, |
| data: strData || '', |
| rId: relId1, |
| isDuplicate: !!(dupeItem?.Target), |
| Target: dupeItem?.Target ? dupeItem.Target : `../media/media-${target._slideNum}-${target._relsMedia.length + 1}.${strExtn}`, |
| }) |
| slideData.mediaRid = relId1 |
|
|
| |
| target._relsMedia.push({ |
| path: strPath || 'preencoded' + strExtn, |
| type: strType + '/' + strExtn, |
| extn: strExtn, |
| data: strData || '', |
| rId: getNewRelId(target), |
| isDuplicate: !!(dupeItem?.Target), |
| Target: dupeItem?.Target ? dupeItem.Target : `../media/media-${target._slideNum}-${target._relsMedia.length + 0}.${strExtn}`, |
| }) |
|
|
| |
| target._relsMedia.push({ |
| path: 'preencoded.png', |
| type: 'image/png', |
| extn: 'png', |
| data: strCover, |
| rId: getNewRelId(target), |
| Target: `../media/image-${target._slideNum}-${target._relsMedia.length + 1}.png`, |
| }) |
| } |
|
|
| |
| target._slideObjects.push(slideData) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function addNotesDefinition(target: PresSlide, notes: string): void { |
| target._slideObjects.push({ |
| _type: SLIDE_OBJECT_TYPES.notes, |
| text: [{ text: notes }], |
| }) |
| } |
|
|
| |
| |
| |
| |
| |
| export function addFormulaDefinition(target: PresSlide, opts: FormulaProps): void { |
| const newObject: ISlideObject = { |
| _type: SLIDE_OBJECT_TYPES.formula, |
| options: { |
| x: opts.x || 0, |
| y: opts.y || 0, |
| w: opts.w, |
| h: opts.h, |
| objectName: opts.objectName |
| ? encodeXmlEntities(opts.objectName) |
| : `Formula ${target._slideObjects.filter((obj) => obj._type === SLIDE_OBJECT_TYPES.formula).length}`, |
| fontSize: opts.fontSize, |
| color: opts.color, |
| }, |
| formula: opts.omml, |
| formulaAlign: opts.align || 'center', |
| } |
| target._slideObjects.push(newObject) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function addShapeDefinition(target: PresSlide, shapeName: SHAPE_NAME, opts: ShapeProps): void { |
| const options = typeof opts === 'object' ? opts : {} |
| options.line = options.line || { type: 'none' } |
| const newObject: ISlideObject = { |
| _type: SLIDE_OBJECT_TYPES.text, |
| shape: shapeName || SHAPE_TYPE.RECTANGLE, |
| options, |
| text: null, |
| } |
|
|
| |
| if (!shapeName) throw new Error('Missing/Invalid shape parameter! Example: `addShape(pptxgen.shapes.LINE, {x:1, y:1, w:1, h:1});`') |
|
|
| |
| const newLineOpts: ShapeLineProps = { |
| type: options.line.type || 'solid', |
| color: options.line.color || DEF_SHAPE_LINE_COLOR, |
| transparency: options.line.transparency || 0, |
| width: options.line.width || 1, |
| dashType: options.line.dashType || 'solid', |
| beginArrowType: options.line.beginArrowType || null, |
| endArrowType: options.line.endArrowType || null, |
| } |
| if (typeof options.line === 'object' && options.line.type !== 'none') options.line = newLineOpts |
|
|
| |
| options.x = options.x || (options.x === 0 ? 0 : 1) |
| options.y = options.y || (options.y === 0 ? 0 : 1) |
| options.w = options.w || (options.w === 0 ? 0 : 1) |
| options.h = options.h || (options.h === 0 ? 0 : 1) |
| options.objectName = options.objectName |
| ? encodeXmlEntities(options.objectName) |
| : `Shape ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.text).length}` |
|
|
| |
| if (typeof options.line === 'string') { |
| const tmpOpts = newLineOpts |
| tmpOpts.color = String(options.line) |
| options.line = tmpOpts |
| } |
| if (typeof options.lineSize === 'number') options.line.width = options.lineSize |
| if (typeof options.lineDash === 'string') options.line.dashType = options.lineDash |
| if (typeof options.lineHead === 'string') options.line.beginArrowType = options.lineHead |
| if (typeof options.lineTail === 'string') options.line.endArrowType = options.lineTail |
|
|
| |
| createHyperlinkRels(target, newObject) |
|
|
| |
| target._slideObjects.push(newObject) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function addTableDefinition( |
| target: PresSlide, |
| tableRows: TableRow[], |
| options: TableProps, |
| slideLayout: SlideLayout, |
| presLayout: PresLayout, |
| addSlide: (options?: AddSlideProps) => PresSlide, |
| getSlide: (slideNumber: number) => PresSlide |
| ): PresSlide[] { |
| const slides: PresSlide[] = [target] |
| const opt: TableProps = options && typeof options === 'object' ? options : {} |
| opt.objectName = opt.objectName ? encodeXmlEntities(opt.objectName) : `Table ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.table).length}` |
|
|
| |
| { |
| |
| if (tableRows === null || tableRows.length === 0 || !Array.isArray(tableRows)) { |
| throw new Error('addTable: Array expected! EX: \'slide.addTable( [rows], {options} );\' (https://gitbrent.github.io/PptxGenJS/docs/api-tables.html)') |
| } |
|
|
| |
| if (!tableRows[0] || !Array.isArray(tableRows[0])) { |
| throw new Error( |
| 'addTable: \'rows\' should be an array of cells! EX: \'slide.addTable( [ [\'A\'], [\'B\'], {text:\'C\',options:{align:\'center\'}} ] );\' (https://gitbrent.github.io/PptxGenJS/docs/api-tables.html)' |
| ) |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| } |
|
|
| |
| |
| const arrRows: TableCell[][] = [] |
| tableRows.forEach(row => { |
| const newRow: TableCell[] = [] |
|
|
| if (Array.isArray(row)) { |
| row.forEach((cell: number | string | TableCell) => { |
| |
| const newCell: TableCell = { |
| _type: SLIDE_OBJECT_TYPES.tablecell, |
| text: '', |
| options: typeof cell === 'object' && cell.options ? cell.options : {}, |
| } |
|
|
| |
| if (typeof cell === 'string' || typeof cell === 'number') newCell.text = cell.toString() |
| else if (cell.text) { |
| |
| if (typeof cell.text === 'string' || typeof cell.text === 'number') newCell.text = cell.text.toString() |
| else if (cell.text) newCell.text = cell.text |
| |
| if (cell.options && typeof cell.options === 'object') newCell.options = cell.options |
| } |
|
|
| |
| newCell.options.border = newCell.options.border || opt.border || [{ type: 'none' }, { type: 'none' }, { type: 'none' }, { type: 'none' }] |
| const cellBorder = newCell.options.border |
|
|
| |
| if (!Array.isArray(cellBorder) && typeof cellBorder === 'object') newCell.options.border = [cellBorder, cellBorder, cellBorder, cellBorder] |
| |
| if (!newCell.options.border[0]) newCell.options.border[0] = { type: 'none' } |
| if (!newCell.options.border[1]) newCell.options.border[1] = { type: 'none' } |
| if (!newCell.options.border[2]) newCell.options.border[2] = { type: 'none' } |
| if (!newCell.options.border[3]) newCell.options.border[3] = { type: 'none' } |
|
|
| |
| const arrSides = [0, 1, 2, 3] |
| arrSides.forEach(idx => { |
| newCell.options.border[idx] = { |
| type: newCell.options.border[idx].type || DEF_CELL_BORDER.type, |
| color: newCell.options.border[idx].color || DEF_CELL_BORDER.color, |
| pt: typeof newCell.options.border[idx].pt === 'number' ? newCell.options.border[idx].pt : DEF_CELL_BORDER.pt, |
| } |
| }) |
|
|
| |
| newRow.push(newCell) |
| }) |
| } else { |
| console.log('addTable: tableRows has a bad row. A row should be an array of cells. You provided:') |
| console.log(row) |
| } |
|
|
| arrRows.push(newRow) |
| }) |
|
|
| |
| opt.x = getSmartParseNumber(opt.x || (opt.x === 0 ? 0 : EMU / 2), 'X', presLayout) |
| opt.y = getSmartParseNumber(opt.y || (opt.y === 0 ? 0 : EMU / 2), 'Y', presLayout) |
| if (opt.h) opt.h = getSmartParseNumber(opt.h, 'Y', presLayout) |
| opt.fontSize = opt.fontSize || DEF_FONT_SIZE |
| opt.margin = opt.margin === 0 || opt.margin ? opt.margin : DEF_CELL_MARGIN_IN |
| if (typeof opt.margin === 'number') opt.margin = [Number(opt.margin), Number(opt.margin), Number(opt.margin), Number(opt.margin)] |
| |
| if (JSON.stringify({ arrRows: arrRows }).indexOf('hyperlink') === -1) { |
| if (!opt.color) opt.color = opt.color || DEF_FONT_COLOR |
| } |
| if (typeof opt.border === 'string') { |
| console.warn('addTable `border` option must be an object. Ex: `{border: {type:\'none\'}}`') |
| opt.border = null |
| } else if (Array.isArray(opt.border)) { |
| [0, 1, 2, 3].forEach(idx => { |
| opt.border[idx] = opt.border[idx] |
| ? { type: opt.border[idx].type || DEF_CELL_BORDER.type, color: opt.border[idx].color || DEF_CELL_BORDER.color, pt: opt.border[idx].pt || DEF_CELL_BORDER.pt } |
| : { type: 'none' } |
| }) |
| } |
|
|
| opt.autoPage = typeof opt.autoPage === 'boolean' ? opt.autoPage : false |
| opt.autoPageRepeatHeader = typeof opt.autoPageRepeatHeader === 'boolean' ? opt.autoPageRepeatHeader : false |
| opt.autoPageHeaderRows = typeof opt.autoPageHeaderRows !== 'undefined' && !isNaN(Number(opt.autoPageHeaderRows)) ? Number(opt.autoPageHeaderRows) : 1 |
| opt.autoPageLineWeight = typeof opt.autoPageLineWeight !== 'undefined' && !isNaN(Number(opt.autoPageLineWeight)) ? Number(opt.autoPageLineWeight) : 0 |
| if (opt.autoPageLineWeight) { |
| if (opt.autoPageLineWeight > 1) opt.autoPageLineWeight = 1 |
| else if (opt.autoPageLineWeight < -1) opt.autoPageLineWeight = -1 |
| } |
| |
|
|
| |
| |
| let arrTableMargin = DEF_SLIDE_MARGIN_IN |
| |
| if (slideLayout && typeof slideLayout._margin !== 'undefined') { |
| if (Array.isArray(slideLayout._margin)) arrTableMargin = slideLayout._margin |
| else if (!isNaN(Number(slideLayout._margin))) { arrTableMargin = [Number(slideLayout._margin), Number(slideLayout._margin), Number(slideLayout._margin), Number(slideLayout._margin)] } |
| } |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| if (opt.colW) { |
| const firstRowColCnt = arrRows[0].reduce((totalLen, c) => { |
| if (c?.options?.colspan && typeof c.options.colspan === 'number') { |
| totalLen += c.options.colspan |
| } else { |
| totalLen += 1 |
| } |
| return totalLen |
| }, 0) |
|
|
| if (typeof opt.colW === 'string' || typeof opt.colW === 'number') { |
| |
| opt.w = Math.floor(Number(opt.colW) * firstRowColCnt) |
| opt.colW = null |
| } else if (opt.colW && Array.isArray(opt.colW) && opt.colW.length === 1 && firstRowColCnt > 1) { |
| |
| opt.w = Math.floor(Number(opt.colW) * firstRowColCnt) |
| opt.colW = null |
| } else if (opt.colW && Array.isArray(opt.colW) && opt.colW.length !== firstRowColCnt) { |
| |
| console.warn('addTable: mismatch: (colW.length != data.length) Therefore, defaulting to evenly distributed col widths.') |
| opt.colW = null |
| } |
| } else if (opt.w) { |
| opt.w = getSmartParseNumber(opt.w, 'X', presLayout) |
| } else { |
| opt.w = Math.floor(presLayout._sizeW / EMU - arrTableMargin[1] - arrTableMargin[3]) |
| } |
|
|
| |
| if (opt.x && opt.x < 20) opt.x = inch2Emu(opt.x) |
| if (opt.y && opt.y < 20) opt.y = inch2Emu(opt.y) |
| if (opt.w && typeof opt.w === 'number' && opt.w < 20) opt.w = inch2Emu(opt.w) |
| if (opt.h && typeof opt.h === 'number' && opt.h < 20) opt.h = inch2Emu(opt.h) |
|
|
| |
| arrRows.forEach(row => { |
| row.forEach((cell, idy) => { |
| |
| |
| |
| |
| |
| |
| |
| |
| if (typeof cell === 'number' || typeof cell === 'string') { |
| |
| row[idy] = { _type: SLIDE_OBJECT_TYPES.tablecell, text: String(row[idy]), options: opt } |
| } else if (typeof cell === 'object') { |
| |
| if (typeof cell.text === 'number') row[idy].text = row[idy].text.toString() |
| else if (typeof cell.text === 'undefined' || cell.text === null) row[idy].text = '' |
|
|
| |
| row[idy].options = cell.options || {} |
|
|
| |
| row[idy]._type = SLIDE_OBJECT_TYPES.tablecell |
| } |
|
|
| |
| |
| |
| |
| |
| }) |
| }) |
|
|
| |
| const newAutoPagedSlides: PresSlide[] = [] |
|
|
| |
| |
| if (opt && !opt.autoPage) { |
| |
| createHyperlinkRels(target, arrRows) |
|
|
| |
| target._slideObjects.push({ |
| _type: SLIDE_OBJECT_TYPES.table, |
| arrTabRows: arrRows, |
| options: Object.assign({}, opt), |
| }) |
| } else { |
| if (opt.autoPageRepeatHeader) opt._arrObjTabHeadRows = arrRows.filter((_row, idx) => idx < opt.autoPageHeaderRows) |
|
|
| |
| getSlidesForTableRows(arrRows, opt, presLayout, slideLayout).forEach((slide, idx) => { |
| |
| if (!getSlide(target._slideNum + idx)) slides.push(addSlide({ masterName: slideLayout?._name || null })) |
|
|
| |
| if (idx > 0) opt.y = inch2Emu(opt.autoPageSlideStartY || opt.newSlideStartY || arrTableMargin[0]) |
|
|
| |
| { |
| const newSlide: PresSlide = getSlide(target._slideNum + idx) |
|
|
| opt.autoPage = false |
|
|
| |
| createHyperlinkRels(newSlide, slide.rows) |
|
|
| |
| newSlide.addTable(slide.rows, Object.assign({}, opt)) |
|
|
| |
| if (idx > 0) newAutoPagedSlides.push(newSlide) |
| } |
| }) |
| } |
| return newAutoPagedSlides |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function addTextDefinition(target: PresSlide, text: TextProps[], opts: TextPropsOptions, isPlaceholder: boolean): void { |
| const newObject: ISlideObject = { |
| _type: isPlaceholder ? SLIDE_OBJECT_TYPES.placeholder : SLIDE_OBJECT_TYPES.text, |
| shape: (opts?.shape) || SHAPE_TYPE.RECTANGLE, |
| text: !text || text.length === 0 ? [{ text: '', options: null }] : text, |
| options: opts || {}, |
| } |
|
|
| function cleanOpts(itemOpts: ObjectOptions): TextPropsOptions { |
| |
| { |
| |
| if (!itemOpts.placeholder) { |
| itemOpts.color = itemOpts.color || newObject.options.color || target.color || DEF_FONT_COLOR |
| } |
|
|
| |
| if (itemOpts.placeholder || isPlaceholder) { |
| itemOpts.bullet = itemOpts.bullet || false |
| } |
|
|
| |
| if (itemOpts.placeholder && target._slideLayout && target._slideLayout._slideObjects) { |
| const placeHold = target._slideLayout._slideObjects.filter( |
| item => item._type === 'placeholder' && item.options && item.options.placeholder && item.options.placeholder === itemOpts.placeholder |
| )[0] |
| if (placeHold?.options) itemOpts = { ...itemOpts, ...placeHold.options } |
| } |
|
|
| |
| itemOpts.objectName = itemOpts.objectName |
| ? encodeXmlEntities(itemOpts.objectName) |
| : `Text ${target._slideObjects.filter(obj => obj._type === SLIDE_OBJECT_TYPES.text).length}` |
|
|
| |
| if (itemOpts.shape === SHAPE_TYPE.LINE) { |
| |
| const newLineOpts: ShapeLineProps = { |
| type: itemOpts.line.type || 'solid', |
| color: itemOpts.line.color || DEF_SHAPE_LINE_COLOR, |
| transparency: itemOpts.line.transparency || 0, |
| width: itemOpts.line.width || 1, |
| dashType: itemOpts.line.dashType || 'solid', |
| beginArrowType: itemOpts.line.beginArrowType || null, |
| endArrowType: itemOpts.line.endArrowType || null, |
| } |
| if (typeof itemOpts.line === 'object') itemOpts.line = newLineOpts |
|
|
| |
| if (typeof itemOpts.line === 'string') { |
| const tmpOpts = newLineOpts |
| if (typeof itemOpts.line === 'string') tmpOpts.color = itemOpts.line |
| |
| itemOpts.line = tmpOpts |
| } |
| if (typeof itemOpts.lineSize === 'number') itemOpts.line.width = itemOpts.lineSize |
| if (typeof itemOpts.lineDash === 'string') itemOpts.line.dashType = itemOpts.lineDash |
| if (typeof itemOpts.lineHead === 'string') itemOpts.line.beginArrowType = itemOpts.lineHead |
| if (typeof itemOpts.lineTail === 'string') itemOpts.line.endArrowType = itemOpts.lineTail |
| } |
|
|
| |
| itemOpts.line = itemOpts.line || {} |
| itemOpts.lineSpacing = itemOpts.lineSpacing && !isNaN(itemOpts.lineSpacing) ? itemOpts.lineSpacing : null |
| itemOpts.lineSpacingMultiple = itemOpts.lineSpacingMultiple && !isNaN(itemOpts.lineSpacingMultiple) ? itemOpts.lineSpacingMultiple : null |
|
|
| |
| itemOpts._bodyProp = itemOpts._bodyProp || {} |
| itemOpts._bodyProp.autoFit = itemOpts.autoFit || false |
| itemOpts._bodyProp.anchor = !itemOpts.placeholder ? TEXT_VALIGN.ctr : null |
| itemOpts._bodyProp.vert = itemOpts.vert || null |
| itemOpts._bodyProp.wrap = typeof itemOpts.wrap === 'boolean' ? itemOpts.wrap : true |
|
|
| |
| |
| if ((itemOpts.inset && !isNaN(Number(itemOpts.inset))) || itemOpts.inset === 0) { |
| itemOpts._bodyProp.lIns = inch2Emu(itemOpts.inset) |
| itemOpts._bodyProp.rIns = inch2Emu(itemOpts.inset) |
| itemOpts._bodyProp.tIns = inch2Emu(itemOpts.inset) |
| itemOpts._bodyProp.bIns = inch2Emu(itemOpts.inset) |
| } |
|
|
| |
| if (typeof itemOpts.underline === 'boolean' && itemOpts.underline === true) itemOpts.underline = { style: 'sng' } |
| } |
|
|
| |
| { |
| if ((itemOpts.align || '').toLowerCase().indexOf('c') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.center |
| else if ((itemOpts.align || '').toLowerCase().indexOf('l') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.left |
| else if ((itemOpts.align || '').toLowerCase().indexOf('r') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.right |
| else if ((itemOpts.align || '').toLowerCase().indexOf('j') === 0) itemOpts._bodyProp.align = TEXT_HALIGN.justify |
|
|
| if ((itemOpts.valign || '').toLowerCase().indexOf('b') === 0) itemOpts._bodyProp.anchor = TEXT_VALIGN.b |
| else if ((itemOpts.valign || '').toLowerCase().indexOf('m') === 0) itemOpts._bodyProp.anchor = TEXT_VALIGN.ctr |
| else if ((itemOpts.valign || '').toLowerCase().indexOf('t') === 0) itemOpts._bodyProp.anchor = TEXT_VALIGN.t |
| } |
|
|
| |
| correctShadowOptions(itemOpts.shadow) |
|
|
| return itemOpts |
| } |
|
|
| |
| newObject.options = cleanOpts(newObject.options) |
|
|
| |
| newObject.text.forEach(item => (item.options = cleanOpts(item.options || {}))) |
|
|
| |
| createHyperlinkRels(target, newObject.text || '') |
|
|
| |
| target._slideObjects.push(newObject) |
| } |
|
|
| |
| |
| |
| |
| export function addPlaceholdersToSlideLayouts(slide: PresSlide): void { |
| |
| (slide._slideLayout._slideObjects || []).forEach(slideLayoutObj => { |
| if (slideLayoutObj._type === SLIDE_OBJECT_TYPES.placeholder) { |
| |
| |
| |
| if (slide._slideObjects.filter(slideObj => slideObj.options && slideObj.options.placeholder === slideLayoutObj.options.placeholder).length === 0) { |
| addTextDefinition(slide, [{ text: '' }], slideLayoutObj.options, false) |
| } |
| } |
| }) |
| } |
|
|
| |
|
|
| |
| |
| |
| |
| |
| export function addBackgroundDefinition(props: BackgroundProps, target: SlideLayout): void { |
| |
| if (target.bkgd) { |
| if (!target.background) target.background = {} |
|
|
| if (typeof target.bkgd === 'string') target.background.color = target.bkgd |
| else { |
| if (target.bkgd.data) target.background.data = target.bkgd.data |
| if (target.bkgd.path) target.background.path = target.bkgd.path |
| if (target.bkgd.src) target.background.path = target.bkgd.src |
| } |
| } |
| if (target.background?.fill) target.background.color = target.background.fill |
|
|
| |
| if (props && (props.path || props.data)) { |
| |
| props.path = props.path || 'preencoded.png' |
| let strImgExtn = (props.path.split('.').pop() || 'png').split('?')[0] |
| if (strImgExtn === 'jpg') strImgExtn = 'jpeg' |
|
|
| target._relsMedia = target._relsMedia || [] |
| const intRels = target._relsMedia.length + 1 |
| |
| target._relsMedia.push({ |
| path: props.path, |
| type: SLIDE_OBJECT_TYPES.image, |
| extn: strImgExtn, |
| data: props.data || null, |
| rId: intRels, |
| Target: `../media/${(target._name || '').replace(/\s+/gi, '-')}-image-${target._relsMedia.length + 1}.${strImgExtn}`, |
| }) |
| target._bkgdImgRid = intRels |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| function createHyperlinkRels( |
| target: PresSlide, |
| text: number | string | ISlideObject | TextProps | TextProps[] | TableCell[][], |
| options?: TextPropsOptions[], |
| ): void { |
| let textObjs = [] |
|
|
| |
| if (typeof text === 'string' || typeof text === 'number') return |
| |
| else if (Array.isArray(text)) textObjs = text |
| else if (typeof text === 'object') textObjs = [text] |
|
|
| textObjs.forEach((text: TextProps, idx: number) => { |
| |
| if (options && options[idx] && options[idx].hyperlink) text.options = { ...text.options, ...options[idx] } |
|
|
| |
| if (Array.isArray(text)) { |
| const cellOpts = [] |
| text.forEach((tablecell) => { |
| if (tablecell.options && !tablecell.text.options) { |
| cellOpts.push(tablecell.options) |
| } |
| }) |
| createHyperlinkRels(target, text, cellOpts) |
| } else if (Array.isArray(text.text)) { |
| createHyperlinkRels(target, text.text, options && options[idx] ? [options[idx]] : undefined) |
| } else if (text && typeof text === 'object' && text.options && text.options.hyperlink && !text.options.hyperlink._rId) { |
| if (typeof text.options.hyperlink !== 'object') { |
| console.log('ERROR: text `hyperlink` option should be an object. Ex: `hyperlink: {url:\'https://github.com\'}` ') |
| } |
| else if (!text.options.hyperlink.url && !text.options.hyperlink.slide) { |
| console.log('ERROR: \'hyperlink requires either: `url` or `slide`\'') |
| } |
| else { |
| const relId = getNewRelId(target) |
|
|
| target._rels.push({ |
| type: SLIDE_OBJECT_TYPES.hyperlink, |
| data: text.options.hyperlink.slide ? 'slide' : 'dummy', |
| rId: relId, |
| Target: encodeXmlEntities(text.options.hyperlink.url) || text.options.hyperlink.slide.toString(), |
| }) |
|
|
| text.options.hyperlink._rId = relId |
| } |
| } |
| else if (text && typeof text === 'object' && text.options && text.options.hyperlink && text.options.hyperlink._rId) { |
| |
| if (target._rels.filter(rel => rel.rId === text.options.hyperlink._rId).length === 0) { |
| target._rels.push({ |
| type: SLIDE_OBJECT_TYPES.hyperlink, |
| data: text.options.hyperlink.slide ? 'slide' : 'dummy', |
| rId: text.options.hyperlink._rId, |
| Target: encodeXmlEntities(text.options.hyperlink.url) || text.options.hyperlink.slide.toString(), |
| }) |
| } |
| } |
| }) |
| } |
|
|