@lofcz/pptxtojson 2.2.4 → 2.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3162,17 +3162,18 @@ function genTextBody(textBodyNode, spNode, slideLayoutSpNode, slideMasterSpNode,
3162
3162
  const align = getHorizontalAlign(pNode, spNode, type, slideLayoutSpNode, slideMasterSpNode, warpObj);
3163
3163
  const spacing = getParagraphSpacing(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3164
3164
  const indent = getParagraphIndent(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3165
- const listType = getListType(pNode);
3165
+ const listType = getListType(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3166
3166
  const listLevel = getListLevel(pNode);
3167
3167
  let alignStyle = align;
3168
3168
  if ('distribute' === align) alignStyle = 'justify';
3169
- let styleText = `text-align: ${alignStyle};line-height: 1.2;`;
3169
+ let styleText = `text-align: ${alignStyle};`;
3170
3170
  if ('distribute' === align) styleText += "text-align-last: justify;text-justify: distribute;";
3171
3171
  if (spacing) {
3172
3172
  if (spacing.lineSpacing) styleText += `line-height: ${spacing.lineSpacing};`;
3173
+ else styleText += "line-height: 1.2;";
3173
3174
  if (spacing.spaceBefore) styleText += `margin-top: ${spacing.spaceBefore};`;
3174
3175
  if (spacing.spaceAfter) styleText += `margin-bottom: ${spacing.spaceAfter};`;
3175
- }
3176
+ } else styleText += "line-height: 1.2;";
3176
3177
  if (indent) {
3177
3178
  if (!listType && indent.marginLeft) styleText += `margin-left: ${indent.marginLeft};`;
3178
3179
  if (!listType && indent.textIndent) styleText += `text-indent: ${indent.textIndent};`;
@@ -3267,19 +3268,21 @@ function getMathRunStyleText(mathRun, siblingRun, pNode, textBodyNode, pFontStyl
3267
3268
  if (fontColor && 'string' == typeof fontColor) styleText += `color: ${fontColor};`;
3268
3269
  return styleText;
3269
3270
  }
3270
- function getListType(node) {
3271
- const pPrNode = node['a:pPr'];
3272
- if (!pPrNode) return '';
3273
- if (pPrNode['a:buNone']) return '';
3271
+ function getListType(node, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
3274
3272
  const hasContent = node['a:r'] || node['a:br'] || node['a:fld'];
3275
3273
  if (!hasContent) return '';
3276
- if (pPrNode['a:buChar']) return 'ul';
3277
- if (pPrNode['a:buAutoNum']) return 'ol';
3274
+ const styleNodes = getParagraphStyleNodes(node, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3275
+ if (!styleNodes) return '';
3276
+ for (const styleNode of styleNodes){
3277
+ if (styleNode['a:buNone']) break;
3278
+ if (styleNode['a:buChar'] || styleNode['a:buBlip']) return 'ul';
3279
+ if (styleNode['a:buAutoNum']) return 'ol';
3280
+ }
3278
3281
  return '';
3279
3282
  }
3280
3283
  function getListLevel(node) {
3281
3284
  const pPrNode = node['a:pPr'];
3282
- if (!pPrNode) return -1;
3285
+ if (!pPrNode) return 0;
3283
3286
  const lvlNode = getTextByPathList(pPrNode, [
3284
3287
  'attrs',
3285
3288
  'lvl'
@@ -3287,6 +3290,30 @@ function getListLevel(node) {
3287
3290
  if (void 0 !== lvlNode) return parseInt(lvlNode);
3288
3291
  return 0;
3289
3292
  }
3293
+ function schemeColorToCss(color) {
3294
+ if (!color) return '';
3295
+ return color.startsWith('#') ? color : `#${color}`;
3296
+ }
3297
+ function applyHyperlinkRunStyle(styleText, node, warpObj) {
3298
+ let next = styleText;
3299
+ const runStyleNode = getTextByPathList(node, [
3300
+ 'a:rPr'
3301
+ ]);
3302
+ const runFill = runStyleNode ? getFillType(runStyleNode) : '';
3303
+ const runHasOwnColor = 'SOLID_FILL' === runFill || 'GRADIENT_FILL' === runFill;
3304
+ if (!runHasOwnColor) {
3305
+ const hlinkColor = schemeColorToCss(getSchemeColorFromTheme('a:hlink', warpObj)) || '#0563C1';
3306
+ if (/color\s*:/.test(next)) next = next.replace(/color\s*:\s*[^;]+;/, `color: ${hlinkColor};`);
3307
+ else next += `color: ${hlinkColor};`;
3308
+ }
3309
+ const runUnderline = getTextByPathList(node, [
3310
+ 'a:rPr',
3311
+ 'attrs',
3312
+ 'u'
3313
+ ]);
3314
+ if ('none' !== runUnderline && !/text-decoration\s*:\s*underline/.test(next)) next += 'text-decoration: underline;';
3315
+ return next;
3316
+ }
3290
3317
  function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, defaultTextStyle, warpObj) {
3291
3318
  const { styleText, text, hasLink, linkURL } = getSpanStyleInfo(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, defaultTextStyle, warpObj);
3292
3319
  const processedText = text.replace(/\t/g, '    ').replace(/\s/g, ' ');
@@ -3343,6 +3370,7 @@ function getSpanStyleInfo(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNo
3343
3370
  'r:id'
3344
3371
  ]);
3345
3372
  const hasLink = linkID && warpObj['slideResObj'][linkID];
3373
+ if (hasLink) styleText = applyHyperlinkRunStyle(styleText, node, warpObj);
3346
3374
  return {
3347
3375
  styleText,
3348
3376
  text,
@@ -9797,21 +9825,62 @@ function sortSlideXml(p1, p2) {
9797
9825
  const n2 = +(/(\d+)\.xml/.exec(p2)?.[1] || 0);
9798
9826
  return n1 - n2;
9799
9827
  }
9800
- function resolvePresentationTarget(target) {
9801
- let relTarget = String(target || '').replace(/\\/g, '/');
9802
- if (!relTarget) return '';
9803
- if (0 === relTarget.indexOf('/ppt/')) return relTarget.substr(1);
9804
- if (-1 !== relTarget.indexOf('../')) return relTarget.replace('../', 'ppt/');
9805
- if (0 === relTarget.indexOf('ppt/')) return relTarget;
9806
- return 'ppt/' + relTarget.replace(/^\//, '');
9828
+ function normalizePartName(name) {
9829
+ return String(name || '').replace(/\\/g, '/').replace(/^\//, '');
9830
+ }
9831
+ function relationshipsPartFor(partName) {
9832
+ const name = normalizePartName(partName);
9833
+ const slash = name.lastIndexOf('/');
9834
+ const dir = -1 === slash ? '' : name.slice(0, slash + 1);
9835
+ const file = -1 === slash ? name : name.slice(slash + 1);
9836
+ return `${dir}_rels/${file}.rels`;
9837
+ }
9838
+ function resolvePartTarget(sourcePart, target) {
9839
+ const raw = String(target || '').replace(/\\/g, '/');
9840
+ if (!raw) return '';
9841
+ if (raw.startsWith('/')) return normalizePartName(raw);
9842
+ const source = normalizePartName(sourcePart);
9843
+ const slash = source.lastIndexOf('/');
9844
+ const dir = -1 === slash ? '' : source.slice(0, slash + 1);
9845
+ const out = [];
9846
+ for (const seg of `${dir}${raw}`.split('/'))if (seg && '.' !== seg) if ('..' === seg) out.pop();
9847
+ else out.push(seg);
9848
+ return out.join('/');
9807
9849
  }
9808
9850
  function relationshipRid(attrs) {
9809
9851
  if (!attrs) return '';
9810
9852
  return attrs['r:id'] || attrs.rId || '';
9811
9853
  }
9854
+ async function getPresentationPart(zip) {
9855
+ const rels = asNodeArray(getTextByPathList(await readXmlFile(zip, '_rels/.rels'), [
9856
+ 'Relationships',
9857
+ 'Relationship'
9858
+ ]));
9859
+ for (const rel of rels){
9860
+ const type = getTextByPathList(rel, [
9861
+ 'attrs',
9862
+ 'Type'
9863
+ ]);
9864
+ const target = getTextByPathList(rel, [
9865
+ 'attrs',
9866
+ 'Target'
9867
+ ]);
9868
+ const targetMode = getTextByPathList(rel, [
9869
+ 'attrs',
9870
+ 'TargetMode'
9871
+ ]);
9872
+ if (!targetMode || 'external' !== String(targetMode).toLowerCase()) {
9873
+ if ('officeDocument' === getRelTypeName(type) && target) {
9874
+ const loc = resolvePartTarget('', target);
9875
+ if (loc) return loc;
9876
+ }
9877
+ }
9878
+ }
9879
+ return 'ppt/presentation.xml';
9880
+ }
9812
9881
  async function getSlidesFromPresentation(zip) {
9813
- const relsContent = await readXmlFile(zip, 'ppt/_rels/presentation.xml.rels');
9814
- const relItems = asNodeArray(getTextByPathList(relsContent, [
9882
+ const presentationPart = await getPresentationPart(zip);
9883
+ const relItems = asNodeArray(getTextByPathList(await readXmlFile(zip, relationshipsPartFor(presentationPart)), [
9815
9884
  'Relationships',
9816
9885
  'Relationship'
9817
9886
  ]));
@@ -9830,14 +9899,19 @@ async function getSlidesFromPresentation(zip) {
9830
9899
  'attrs',
9831
9900
  'Target'
9832
9901
  ]);
9902
+ const targetMode = getTextByPathList(rel, [
9903
+ 'attrs',
9904
+ 'TargetMode'
9905
+ ]);
9833
9906
  if (!id || !target) continue;
9834
- const loc = resolvePresentationTarget(target);
9907
+ if (targetMode && 'external' === String(targetMode).toLowerCase()) continue;
9908
+ const loc = resolvePartTarget(presentationPart, target);
9835
9909
  if (loc) {
9836
9910
  relsMap[id] = loc;
9837
9911
  if ('slide' === getRelTypeName(type)) slideTargets.push(loc);
9838
9912
  }
9839
9913
  }
9840
- const presentation = await readXmlFile(zip, 'ppt/presentation.xml');
9914
+ const presentation = await readXmlFile(zip, presentationPart);
9841
9915
  const sldIds = asNodeArray(getTextByPathList(presentation, [
9842
9916
  'p:presentation',
9843
9917
  'p:sldIdLst',
@@ -9849,7 +9923,7 @@ async function getSlidesFromPresentation(zip) {
9849
9923
  if (rid && relsMap[rid]) ordered.push(relsMap[rid]);
9850
9924
  }
9851
9925
  if (ordered.length) return ordered;
9852
- return slideTargets.sort(sortSlideXml);
9926
+ return slideTargets;
9853
9927
  }
9854
9928
  async function getContentTypes(zip) {
9855
9929
  const ContentTypesJson = await readXmlFile(zip, '[Content_Types].xml');
@@ -9857,7 +9931,7 @@ async function getContentTypes(zip) {
9857
9931
  'Types',
9858
9932
  'Override'
9859
9933
  ]));
9860
- let slidesLocArray = [];
9934
+ const overrideSlides = [];
9861
9935
  let slideLayoutsLocArray = [];
9862
9936
  for (const item of overrides){
9863
9937
  const contentType = item?.attrs?.ContentType;
@@ -9866,7 +9940,7 @@ async function getContentTypes(zip) {
9866
9940
  const loc = String(partName).replace(/^\//, '');
9867
9941
  switch(contentType){
9868
9942
  case 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml':
9869
- slidesLocArray.push(loc);
9943
+ overrideSlides.push(loc);
9870
9944
  break;
9871
9945
  case 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml':
9872
9946
  slideLayoutsLocArray.push(loc);
@@ -9874,9 +9948,9 @@ async function getContentTypes(zip) {
9874
9948
  default:
9875
9949
  }
9876
9950
  }
9877
- slidesLocArray = slidesLocArray.sort(sortSlideXml);
9878
9951
  slideLayoutsLocArray = slideLayoutsLocArray.sort(sortSlideXml);
9879
- if (!slidesLocArray.length) slidesLocArray = await getSlidesFromPresentation(zip);
9952
+ let slidesLocArray = await getSlidesFromPresentation(zip);
9953
+ if (!slidesLocArray.length) slidesLocArray = overrideSlides.sort(sortSlideXml);
9880
9954
  return {
9881
9955
  slides: slidesLocArray,
9882
9956
  slideLayouts: slideLayoutsLocArray