@@ -16,6 +16,7 @@ import {
1616 ShapeModificationCallback ,
1717 ShapeTargetType ,
1818 SlideModificationCallback ,
19+ SlidePlaceholder ,
1920 SourceIdentifier ,
2021 StatusTracker ,
2122} from '../types/types' ;
@@ -34,7 +35,6 @@ import { Image } from '../shapes/image';
3435import { ElementType } from '../enums/element-type' ;
3536import { GenericShape } from '../shapes/generic' ;
3637import { XmlSlideHelper } from '../helper/xml-slide-helper' ;
37- import { vd } from '../helper/general-helper' ;
3838import { OLEObject } from '../shapes/ole' ;
3939
4040export default class HasShapes {
@@ -130,7 +130,7 @@ export default class HasShapes {
130130 * @internal
131131 */
132132 unsupportedRelationTypes = [
133- // 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject',
133+ // 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject',
134134 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing' ,
135135 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/tags' ,
136136 ] ;
@@ -412,11 +412,9 @@ export default class HasShapes {
412412 ) ;
413413 break ;
414414 case ElementType . OLEObject :
415- await new OLEObject ( info , this . targetType , this . sourceArchive ) [ info . mode ] (
416- this . targetTemplate ,
417- this . targetNumber ,
418- this . targetType ,
419- ) ;
415+ await new OLEObject ( info , this . targetType , this . sourceArchive ) [
416+ info . mode
417+ ] ( this . targetTemplate , this . targetNumber , this . targetType ) ;
420418 break ;
421419 default :
422420 break ;
@@ -785,25 +783,27 @@ export default class HasShapes {
785783 sourceArchive : this . sourceArchive ,
786784 sourceSlideNumber : this . sourceNumber ,
787785 } ,
788- this . targetType
786+ this . targetType ,
789787 ) . modifyOnAddedSlide ( this . targetTemplate , this . targetNumber ) ;
790788 }
791789
792790 const images = await Image . getAllOnSlide ( this . sourceArchive , this . relsPath ) ;
793791 for ( const image of images ) {
794-
795792 await new Image (
796793 {
797794 mode : 'append' ,
798795 target : image ,
799796 sourceArchive : this . sourceArchive ,
800797 sourceSlideNumber : this . sourceNumber ,
801798 } ,
802- this . targetType
799+ this . targetType ,
803800 ) . modifyOnAddedSlide ( this . targetTemplate , this . targetNumber ) ;
804801 }
805802
806- const oleObjects = await OLEObject . getAllOnSlide ( this . sourceArchive , this . relsPath ) ;
803+ const oleObjects = await OLEObject . getAllOnSlide (
804+ this . sourceArchive ,
805+ this . relsPath ,
806+ ) ;
807807 for ( const oleObject of oleObjects ) {
808808 await new OLEObject (
809809 {
@@ -813,7 +813,7 @@ export default class HasShapes {
813813 sourceSlideNumber : this . sourceNumber ,
814814 } ,
815815 this . targetType ,
816- this . sourceArchive
816+ this . sourceArchive ,
817817 ) . modifyOnAddedSlide ( this . targetTemplate , this . targetNumber , oleObjects ) ;
818818 }
819819 }
@@ -881,7 +881,7 @@ export default class HasShapes {
881881 sourceArchive ,
882882 relsPath ,
883883 sourceElement ,
884- 'oleObject'
884+ 'oleObject' ,
885885 ) ;
886886
887887 return {
@@ -930,12 +930,20 @@ export default class HasShapes {
930930 * be processed by pptx-automizer at the moment.
931931 * @internal
932932 */
933- async cleanSlide ( targetPath : string ) : Promise < void > {
933+ async cleanSlide (
934+ targetPath : string ,
935+ sourcePlaceholderTypes ?: SlidePlaceholder [ ] ,
936+ ) : Promise < void > {
934937 const xml = await XmlHelper . getXmlFromArchive (
935938 this . targetArchive ,
936939 targetPath ,
937940 ) ;
938941
942+ if ( sourcePlaceholderTypes ) {
943+ this . removeDuplicatePlaceholders ( xml , sourcePlaceholderTypes ) ;
944+ this . normalizePlaceholderShapes ( xml , sourcePlaceholderTypes ) ;
945+ }
946+
939947 this . unsupportedTags . forEach ( ( tag ) => {
940948 const drop = xml . getElementsByTagName ( tag ) ;
941949 const length = drop . length ;
@@ -946,6 +954,66 @@ export default class HasShapes {
946954 XmlHelper . writeXmlToArchive ( this . targetArchive , targetPath , xml ) ;
947955 }
948956
957+ /**
958+ * If you insert a placeholder shape on a target slide with an empty
959+ * placeholder of the same type, we need to remove the existing
960+ * placeholder.
961+ *
962+ * @param xml
963+ * @param sourcePlaceholderTypes
964+ */
965+ removeDuplicatePlaceholders (
966+ xml : XmlDocument ,
967+ sourcePlaceholderTypes : SlidePlaceholder [ ] ,
968+ ) {
969+ const placeholders = xml . getElementsByTagName ( 'p:ph' ) ;
970+ const usedTypes = { } ;
971+ XmlHelper . modifyCollection ( placeholders , ( placeholder : XmlElement ) => {
972+ const type = placeholder . getAttribute ( 'type' ) ;
973+ usedTypes [ type ] = usedTypes [ type ] || 0 ;
974+ usedTypes [ type ] ++ ;
975+ } ) ;
976+
977+ for ( const usedType in usedTypes ) {
978+ const count = usedTypes [ usedType ] ;
979+ if ( count > 1 ) {
980+ // TODO: in case more than two placeholders are of a kind,
981+ // this will likely remove more than intended. Should also match by id.
982+ const removePlaceholders = sourcePlaceholderTypes . filter (
983+ ( sourcePlaceholder ) => sourcePlaceholder . type === usedType ,
984+ ) ;
985+ removePlaceholders . forEach ( ( removePlaceholder ) => {
986+ const removePlaceholderShape = removePlaceholder . xml . parentNode
987+ . parentNode . parentNode as XmlElement ;
988+ XmlHelper . remove ( removePlaceholderShape ) ;
989+ } ) ;
990+ }
991+ }
992+ }
993+
994+ /**
995+ * If a placeholder shape was inserted on a slide without a corresponding
996+ * placeholder, powerPoint will usually smash the shape's formatting.
997+ * This function removes the placeholder tag.
998+ * @param xml
999+ * @param sourcePlaceholderTypes
1000+ */
1001+ normalizePlaceholderShapes (
1002+ xml : XmlDocument ,
1003+ sourcePlaceholderTypes : SlidePlaceholder [ ] ,
1004+ ) {
1005+ const placeholders = xml . getElementsByTagName ( 'p:ph' ) ;
1006+ XmlHelper . modifyCollection ( placeholders , ( placeholder : XmlElement ) => {
1007+ const usedType = placeholder . getAttribute ( 'type' ) ;
1008+ const existingPlaceholder = sourcePlaceholderTypes . find (
1009+ ( sourcePlaceholder ) => sourcePlaceholder . type === usedType ,
1010+ ) ;
1011+ if ( ! existingPlaceholder ) {
1012+ XmlHelper . remove ( placeholder ) ;
1013+ }
1014+ } ) ;
1015+ }
1016+
9491017 /**
9501018 * Removes all unsupported relations from _rels xml.
9511019 * @internal
@@ -962,4 +1030,21 @@ export default class HasShapes {
9621030 } ,
9631031 } ) ;
9641032 }
1033+
1034+ async parsePlaceholders ( ) : Promise < SlidePlaceholder [ ] > {
1035+ const xml = await XmlHelper . getXmlFromArchive (
1036+ this . targetArchive ,
1037+ this . targetPath ,
1038+ ) ;
1039+ const placeholderTypes = [ ] ;
1040+ const placeholders = xml . getElementsByTagName ( 'p:ph' ) ;
1041+ XmlHelper . modifyCollection ( placeholders , ( placeholder : XmlElement ) => {
1042+ placeholderTypes . push ( {
1043+ type : placeholder . getAttribute ( 'type' ) ,
1044+ id : placeholder . getAttribute ( 'id' ) ,
1045+ xml : placeholder ,
1046+ } ) ;
1047+ } ) ;
1048+ return placeholderTypes ;
1049+ }
9651050}
0 commit comments