@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.cjs CHANGED
@@ -3194,17 +3194,18 @@ function genTextBody(textBodyNode, spNode, slideLayoutSpNode, slideMasterSpNode,
3194
3194
  const align = getHorizontalAlign(pNode, spNode, type, slideLayoutSpNode, slideMasterSpNode, warpObj);
3195
3195
  const spacing = getParagraphSpacing(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3196
3196
  const indent = getParagraphIndent(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3197
- const listType = getListType(pNode);
3197
+ const listType = getListType(pNode, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3198
3198
  const listLevel = getListLevel(pNode);
3199
3199
  let alignStyle = align;
3200
3200
  if ('distribute' === align) alignStyle = 'justify';
3201
- let styleText = `text-align: ${alignStyle};line-height: 1.2;`;
3201
+ let styleText = `text-align: ${alignStyle};`;
3202
3202
  if ('distribute' === align) styleText += "text-align-last: justify;text-justify: distribute;";
3203
3203
  if (spacing) {
3204
3204
  if (spacing.lineSpacing) styleText += `line-height: ${spacing.lineSpacing};`;
3205
+ else styleText += "line-height: 1.2;";
3205
3206
  if (spacing.spaceBefore) styleText += `margin-top: ${spacing.spaceBefore};`;
3206
3207
  if (spacing.spaceAfter) styleText += `margin-bottom: ${spacing.spaceAfter};`;
3207
- }
3208
+ } else styleText += "line-height: 1.2;";
3208
3209
  if (indent) {
3209
3210
  if (!listType && indent.marginLeft) styleText += `margin-left: ${indent.marginLeft};`;
3210
3211
  if (!listType && indent.textIndent) styleText += `text-indent: ${indent.textIndent};`;
@@ -3299,19 +3300,21 @@ function getMathRunStyleText(mathRun, siblingRun, pNode, textBodyNode, pFontStyl
3299
3300
  if (fontColor && 'string' == typeof fontColor) styleText += `color: ${fontColor};`;
3300
3301
  return styleText;
3301
3302
  }
3302
- function getListType(node) {
3303
- const pPrNode = node['a:pPr'];
3304
- if (!pPrNode) return '';
3305
- if (pPrNode['a:buNone']) return '';
3303
+ function getListType(node, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj) {
3306
3304
  const hasContent = node['a:r'] || node['a:br'] || node['a:fld'];
3307
3305
  if (!hasContent) return '';
3308
- if (pPrNode['a:buChar']) return 'ul';
3309
- if (pPrNode['a:buAutoNum']) return 'ol';
3306
+ const styleNodes = getParagraphStyleNodes(node, textBodyNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, warpObj);
3307
+ if (!styleNodes) return '';
3308
+ for (const styleNode of styleNodes){
3309
+ if (styleNode['a:buNone']) break;
3310
+ if (styleNode['a:buChar'] || styleNode['a:buBlip']) return 'ul';
3311
+ if (styleNode['a:buAutoNum']) return 'ol';
3312
+ }
3310
3313
  return '';
3311
3314
  }
3312
3315
  function getListLevel(node) {
3313
3316
  const pPrNode = node['a:pPr'];
3314
- if (!pPrNode) return -1;
3317
+ if (!pPrNode) return 0;
3315
3318
  const lvlNode = getTextByPathList(pPrNode, [
3316
3319
  'attrs',
3317
3320
  'lvl'
@@ -3319,6 +3322,30 @@ function getListLevel(node) {
3319
3322
  if (void 0 !== lvlNode) return parseInt(lvlNode);
3320
3323
  return 0;
3321
3324
  }
3325
+ function schemeColorToCss(color) {
3326
+ if (!color) return '';
3327
+ return color.startsWith('#') ? color : `#${color}`;
3328
+ }
3329
+ function applyHyperlinkRunStyle(styleText, node, warpObj) {
3330
+ let next = styleText;
3331
+ const runStyleNode = getTextByPathList(node, [
3332
+ 'a:rPr'
3333
+ ]);
3334
+ const runFill = runStyleNode ? getFillType(runStyleNode) : '';
3335
+ const runHasOwnColor = 'SOLID_FILL' === runFill || 'GRADIENT_FILL' === runFill;
3336
+ if (!runHasOwnColor) {
3337
+ const hlinkColor = schemeColorToCss(getSchemeColorFromTheme('a:hlink', warpObj)) || '#0563C1';
3338
+ if (/color\s*:/.test(next)) next = next.replace(/color\s*:\s*[^;]+;/, `color: ${hlinkColor};`);
3339
+ else next += `color: ${hlinkColor};`;
3340
+ }
3341
+ const runUnderline = getTextByPathList(node, [
3342
+ 'a:rPr',
3343
+ 'attrs',
3344
+ 'u'
3345
+ ]);
3346
+ if ('none' !== runUnderline && !/text-decoration\s*:\s*underline/.test(next)) next += 'text-decoration: underline;';
3347
+ return next;
3348
+ }
3322
3349
  function genSpanElement(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, defaultTextStyle, warpObj) {
3323
3350
  const { styleText, text, hasLink, linkURL } = getSpanStyleInfo(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles, defaultTextStyle, warpObj);
3324
3351
  const processedText = text.replace(/\t/g, '    ').replace(/\s/g, ' ');
@@ -3375,6 +3402,7 @@ function getSpanStyleInfo(node, pNode, textBodyNode, pFontStyle, slideLayoutSpNo
3375
3402
  'r:id'
3376
3403
  ]);
3377
3404
  const hasLink = linkID && warpObj['slideResObj'][linkID];
3405
+ if (hasLink) styleText = applyHyperlinkRunStyle(styleText, node, warpObj);
3378
3406
  return {
3379
3407
  styleText,
3380
3408
  text,
@@ -9829,21 +9857,62 @@ function sortSlideXml(p1, p2) {
9829
9857
  const n2 = +(/(\d+)\.xml/.exec(p2)?.[1] || 0);
9830
9858
  return n1 - n2;
9831
9859
  }
9832
- function resolvePresentationTarget(target) {
9833
- let relTarget = String(target || '').replace(/\\/g, '/');
9834
- if (!relTarget) return '';
9835
- if (0 === relTarget.indexOf('/ppt/')) return relTarget.substr(1);
9836
- if (-1 !== relTarget.indexOf('../')) return relTarget.replace('../', 'ppt/');
9837
- if (0 === relTarget.indexOf('ppt/')) return relTarget;
9838
- return 'ppt/' + relTarget.replace(/^\//, '');
9860
+ function normalizePartName(name) {
9861
+ return String(name || '').replace(/\\/g, '/').replace(/^\//, '');
9862
+ }
9863
+ function relationshipsPartFor(partName) {
9864
+ const name = normalizePartName(partName);
9865
+ const slash = name.lastIndexOf('/');
9866
+ const dir = -1 === slash ? '' : name.slice(0, slash + 1);
9867
+ const file = -1 === slash ? name : name.slice(slash + 1);
9868
+ return `${dir}_rels/${file}.rels`;
9869
+ }
9870
+ function resolvePartTarget(sourcePart, target) {
9871
+ const raw = String(target || '').replace(/\\/g, '/');
9872
+ if (!raw) return '';
9873
+ if (raw.startsWith('/')) return normalizePartName(raw);
9874
+ const source = normalizePartName(sourcePart);
9875
+ const slash = source.lastIndexOf('/');
9876
+ const dir = -1 === slash ? '' : source.slice(0, slash + 1);
9877
+ const out = [];
9878
+ for (const seg of `${dir}${raw}`.split('/'))if (seg && '.' !== seg) if ('..' === seg) out.pop();
9879
+ else out.push(seg);
9880
+ return out.join('/');
9839
9881
  }
9840
9882
  function relationshipRid(attrs) {
9841
9883
  if (!attrs) return '';
9842
9884
  return attrs['r:id'] || attrs.rId || '';
9843
9885
  }
9886
+ async function getPresentationPart(zip) {
9887
+ const rels = asNodeArray(getTextByPathList(await readXmlFile(zip, '_rels/.rels'), [
9888
+ 'Relationships',
9889
+ 'Relationship'
9890
+ ]));
9891
+ for (const rel of rels){
9892
+ const type = getTextByPathList(rel, [
9893
+ 'attrs',
9894
+ 'Type'
9895
+ ]);
9896
+ const target = getTextByPathList(rel, [
9897
+ 'attrs',
9898
+ 'Target'
9899
+ ]);
9900
+ const targetMode = getTextByPathList(rel, [
9901
+ 'attrs',
9902
+ 'TargetMode'
9903
+ ]);
9904
+ if (!targetMode || 'external' !== String(targetMode).toLowerCase()) {
9905
+ if ('officeDocument' === getRelTypeName(type) && target) {
9906
+ const loc = resolvePartTarget('', target);
9907
+ if (loc) return loc;
9908
+ }
9909
+ }
9910
+ }
9911
+ return 'ppt/presentation.xml';
9912
+ }
9844
9913
  async function getSlidesFromPresentation(zip) {
9845
- const relsContent = await readXmlFile(zip, 'ppt/_rels/presentation.xml.rels');
9846
- const relItems = asNodeArray(getTextByPathList(relsContent, [
9914
+ const presentationPart = await getPresentationPart(zip);
9915
+ const relItems = asNodeArray(getTextByPathList(await readXmlFile(zip, relationshipsPartFor(presentationPart)), [
9847
9916
  'Relationships',
9848
9917
  'Relationship'
9849
9918
  ]));
@@ -9862,14 +9931,19 @@ async function getSlidesFromPresentation(zip) {
9862
9931
  'attrs',
9863
9932
  'Target'
9864
9933
  ]);
9934
+ const targetMode = getTextByPathList(rel, [
9935
+ 'attrs',
9936
+ 'TargetMode'
9937
+ ]);
9865
9938
  if (!id || !target) continue;
9866
- const loc = resolvePresentationTarget(target);
9939
+ if (targetMode && 'external' === String(targetMode).toLowerCase()) continue;
9940
+ const loc = resolvePartTarget(presentationPart, target);
9867
9941
  if (loc) {
9868
9942
  relsMap[id] = loc;
9869
9943
  if ('slide' === getRelTypeName(type)) slideTargets.push(loc);
9870
9944
  }
9871
9945
  }
9872
- const presentation = await readXmlFile(zip, 'ppt/presentation.xml');
9946
+ const presentation = await readXmlFile(zip, presentationPart);
9873
9947
  const sldIds = asNodeArray(getTextByPathList(presentation, [
9874
9948
  'p:presentation',
9875
9949
  'p:sldIdLst',
@@ -9881,7 +9955,7 @@ async function getSlidesFromPresentation(zip) {
9881
9955
  if (rid && relsMap[rid]) ordered.push(relsMap[rid]);
9882
9956
  }
9883
9957
  if (ordered.length) return ordered;
9884
- return slideTargets.sort(sortSlideXml);
9958
+ return slideTargets;
9885
9959
  }
9886
9960
  async function getContentTypes(zip) {
9887
9961
  const ContentTypesJson = await readXmlFile(zip, '[Content_Types].xml');
@@ -9889,7 +9963,7 @@ async function getContentTypes(zip) {
9889
9963
  'Types',
9890
9964
  'Override'
9891
9965
  ]));
9892
- let slidesLocArray = [];
9966
+ const overrideSlides = [];
9893
9967
  let slideLayoutsLocArray = [];
9894
9968
  for (const item of overrides){
9895
9969
  const contentType = item?.attrs?.ContentType;
@@ -9898,7 +9972,7 @@ async function getContentTypes(zip) {
9898
9972
  const loc = String(partName).replace(/^\//, '');
9899
9973
  switch(contentType){
9900
9974
  case 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml':
9901
- slidesLocArray.push(loc);
9975
+ overrideSlides.push(loc);
9902
9976
  break;
9903
9977
  case 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml':
9904
9978
  slideLayoutsLocArray.push(loc);
@@ -9906,9 +9980,9 @@ async function getContentTypes(zip) {
9906
9980
  default:
9907
9981
  }
9908
9982
  }
9909
- slidesLocArray = slidesLocArray.sort(sortSlideXml);
9910
9983
  slideLayoutsLocArray = slideLayoutsLocArray.sort(sortSlideXml);
9911
- if (!slidesLocArray.length) slidesLocArray = await getSlidesFromPresentation(zip);
9984
+ let slidesLocArray = await getSlidesFromPresentation(zip);
9985
+ if (!slidesLocArray.length) slidesLocArray = overrideSlides.sort(sortSlideXml);
9912
9986
  return {
9913
9987
  slides: slidesLocArray,
9914
9988
  slideLayouts: slideLayoutsLocArray