pptx-automizer icon indicating copy to clipboard operation
pptx-automizer copied to clipboard

`useSlideLayout` from root

Open jhaase1 opened this issue 1 year ago • 3 comments

I want to useSlideLayout from the root directory rather than the source presentation? I can hardcode the mapping; however, it would be more elegant to address root/Side Banner/Title Slide or root/No Side Banner/Title Only rather than 1 or 8

If this isn't possible I can work around it, just a nice to have

jhaase1 avatar Dec 18 '24 03:12 jhaase1

Did you try https://github.com/singerla/pptx-automizer/blob/f4ec662b94b4c01bca7ee5f9f088bd8b07a460d0/src/classes/slide.ts#L117

Please let me know if this already helps or if we should improve this more.

singerla avatar Dec 25 '24 22:12 singerla

that's close. I was looking to be able to switch between templates. I'll work on generalizing my code and make a PR

https://github.com/jhaase1/presentation_creator/blob/d90595181aec86dd54b6db7c16ed0a47acf1af79/src/main/powerpoint/copySlidesToPPTX.js#L107-L127

jhaase1 avatar Dec 26 '24 03:12 jhaase1

I'm working on generalizing my code and am getting blocked by my lack of JS knowledge. There are probably a million ways that this is completely inefficient but it has some ideas


async function getMasterName(archive, number) {
  const XML = await XmlHelper.getXmlFromArchive(
    archive,
    `ppt/theme/theme${number}.xml`,
  );

  const layout = XML.getElementsByTagName('a:theme')?.item(0);
  if (layout) {
    const name = layout.getAttribute('name');
    return name;
  }
}

async function getLayoutName(archive, number) {
  const XML = await XmlHelper.getXmlFromArchive(
    archive,
    `ppt/slideLayouts/slideLayout${number}.xml`,
  );

  const layout = XML.getElementsByTagName('p:cSld')?.item(0);
  if (layout) {
    const name = layout.getAttribute('name');
    return name;
  }
}

async function getAllMasterNames(archive) {
  const masterNames = [];
  let number = 1;
  let name;

  while ((name = await getMasterName(archive, number)) !== null) {
    masterNames.push(name);
    number++;
  }

  return masterNames;
}

async function getAllLayoutNames(archive) {
  const layoutNames = [];
  let number = 1;
  let name;

  while ((name = await getLayoutName(archive, number)) !== null) {
    layoutNames.push(name);
    number++;
  }

  return layoutNames;
}

async function slide_getHierarchy(slide) {
  // Get source slide layout id
  const sourceLayoutId = await XmlRelationshipHelper.getSlideLayoutNumber(
    slide.sourceTemplate.archive,
    slide.sourceNumber,
  );

  // Get source master id
  const sourceMasterId = await XmlRelationshipHelper.getSlideMasterNumber(
    slide.sourceTemplate.archive,
    sourceLayoutId,
  );

  const slideMasterName = await getMasterName(
    slide.sourceTemplate.archive,
    sourceMasterId,
  );

  const slideLayoutName = await getLayoutName(
    slide.sourceTemplate.archive,
    sourceLayoutId,
  );

  return {
    layoutId: sourceLayoutId,
    layoutName: slideLayoutName,
    masterId: sourceMasterId,
    masterName: slideMasterName,
    templateName: slide.sourceTemplate.name,
  };
}

async function template_getMasterByName(template, masterName) {
  const masterNames = await getAllMasterNames(template.archive);
  const masterId = masterNames.find((name) => name === masterName);

  return {
    masterName: masterName,
    masterId: masterId,
    master: template.masters[masterId],
  };
}

async function master_getLayoutByName(master, layoutName) {
  const layoutNames = await getAllLayoutNames(master);
  const layoutId = layoutNames.find((name) => name === layoutName);

  return {
    layoutName: layoutName,
    layoutId: layoutId,
    layout: master.layouts[layoutId],
  };
}

async function useNamedSlideLayout(
  slide,
  target = {
    layoutId: null,
    layoutName: null,
    masterId: null,
    masterName: null,
    templateName: null,
  },
) {
  const source = await slide_getHierarchy(slide);

  const templateName = target.templateName || source.templateName;
  const masterName = target.masterName || source.masterName;
  const layoutName = target.layoutName || source.layoutName;

  const template = slide.root.getTemplate(templateName);
  const masterInfo = await template_getMasterByName(template, masterName);
  const layoutInfo = await master_getLayoutByName(masterInfo.master, layoutName);

  await slide.autoImportSourceSlideMaster(templateName, layoutInfo.layoutId);

  const alreadyImported = slide.targetTemplate.getNamedMappedContent(
    'slideLayout',
    layoutName,
  );

  if (!alreadyImported) {
    console.error(
      `Could not find "${layoutName}"@${templateName}@` +
        `sourceLayoutId:${layoutInfo.layoutId}`,
    );
  }

  return alreadyImported?.targetId;
}

jhaase1 avatar Jan 19 '25 02:01 jhaase1