@@ -43,6 +43,11 @@ class Html
43
43
44
44
protected static $ options ;
45
45
46
+ /**
47
+ * @var Css
48
+ */
49
+ protected static $ css ;
50
+
46
51
/**
47
52
* Add HTML parts.
48
53
*
@@ -149,6 +154,16 @@ protected static function parseInlineStyle($node, $styles = [])
149
154
}
150
155
}
151
156
157
+ $ attributeIdentifier = $ attributes ->getNamedItem ('id ' );
158
+ if ($ attributeIdentifier && self ::$ css ) {
159
+ $ styles = self ::parseStyleDeclarations (self ::$ css ->getStyle ('# ' . $ attributeIdentifier ->value ), $ styles );
160
+ }
161
+
162
+ $ attributeClass = $ attributes ->getNamedItem ('class ' );
163
+ if ($ attributeClass && self ::$ css ) {
164
+ $ styles = self ::parseStyleDeclarations (self ::$ css ->getStyle ('. ' . $ attributeClass ->value ), $ styles );
165
+ }
166
+
152
167
$ attributeStyle = $ attributes ->getNamedItem ('style ' );
153
168
if ($ attributeStyle ) {
154
169
$ styles = self ::parseStyle ($ attributeStyle , $ styles );
@@ -168,6 +183,13 @@ protected static function parseInlineStyle($node, $styles = [])
168
183
*/
169
184
protected static function parseNode ($ node , $ element , $ styles = [], $ data = []): void
170
185
{
186
+ if ($ node ->nodeName == 'style ' ) {
187
+ self ::$ css = new Css ($ node ->textContent );
188
+ self ::$ css ->process ();
189
+
190
+ return ;
191
+ }
192
+
171
193
// Populate styles array
172
194
$ styleTypes = ['font ' , 'paragraph ' , 'list ' , 'table ' , 'row ' , 'cell ' ];
173
195
foreach ($ styleTypes as $ styleType ) {
@@ -635,13 +657,21 @@ protected static function parseStyle($attribute, $styles)
635
657
{
636
658
$ properties = explode ('; ' , trim ($ attribute ->value , " \t\n\r\0\x0B; " ));
637
659
660
+ $ selectors = [];
638
661
foreach ($ properties as $ property ) {
639
662
[$ cKey , $ cValue ] = array_pad (explode (': ' , $ property , 2 ), 2 , null );
640
- $ cValue = trim ($ cValue ?? '' );
641
- $ cKey = strtolower (trim ($ cKey ));
642
- switch ($ cKey ) {
663
+ $ selectors [strtolower (trim ($ cKey ))] = trim ($ cValue ?? '' );
664
+ }
665
+
666
+ return self ::parseStyleDeclarations ($ selectors , $ styles );
667
+ }
668
+
669
+ protected static function parseStyleDeclarations (array $ selectors , array $ styles )
670
+ {
671
+ foreach ($ selectors as $ property => $ value ) {
672
+ switch ($ property ) {
643
673
case 'text-decoration ' :
644
- switch ($ cValue ) {
674
+ switch ($ value ) {
645
675
case 'underline ' :
646
676
$ styles ['underline ' ] = 'single ' ;
647
677
@@ -654,44 +684,44 @@ protected static function parseStyle($attribute, $styles)
654
684
655
685
break ;
656
686
case 'text-align ' :
657
- $ styles ['alignment ' ] = self ::mapAlign ($ cValue );
687
+ $ styles ['alignment ' ] = self ::mapAlign ($ value );
658
688
659
689
break ;
660
690
case 'display ' :
661
- $ styles ['hidden ' ] = $ cValue === 'none ' || $ cValue === 'hidden ' ;
691
+ $ styles ['hidden ' ] = $ value === 'none ' || $ value === 'hidden ' ;
662
692
663
693
break ;
664
694
case 'direction ' :
665
- $ styles ['rtl ' ] = $ cValue === 'rtl ' ;
695
+ $ styles ['rtl ' ] = $ value === 'rtl ' ;
666
696
667
697
break ;
668
698
case 'font-size ' :
669
- $ styles ['size ' ] = Converter::cssToPoint ($ cValue );
699
+ $ styles ['size ' ] = Converter::cssToPoint ($ value );
670
700
671
701
break ;
672
702
case 'font-family ' :
673
- $ cValue = array_map ('trim ' , explode (', ' , $ cValue ));
674
- $ styles ['name ' ] = ucwords ($ cValue [0 ]);
703
+ $ value = array_map ('trim ' , explode (', ' , $ value ));
704
+ $ styles ['name ' ] = ucwords ($ value [0 ]);
675
705
676
706
break ;
677
707
case 'color ' :
678
- $ styles ['color ' ] = trim ($ cValue , '# ' );
708
+ $ styles ['color ' ] = trim ($ value , '# ' );
679
709
680
710
break ;
681
711
case 'background-color ' :
682
- $ styles ['bgColor ' ] = trim ($ cValue , '# ' );
712
+ $ styles ['bgColor ' ] = trim ($ value , '# ' );
683
713
684
714
break ;
685
715
case 'line-height ' :
686
716
$ matches = [];
687
- if ($ cValue === 'normal ' ) {
717
+ if ($ value === 'normal ' ) {
688
718
$ spacingLineRule = \PhpOffice \PhpWord \SimpleType \LineSpacingRule::AUTO ;
689
719
$ spacing = 0 ;
690
- } elseif (preg_match ('/([0-9]+\.?[0-9]*[a-z]+)/ ' , $ cValue , $ matches )) {
720
+ } elseif (preg_match ('/([0-9]+\.?[0-9]*[a-z]+)/ ' , $ value , $ matches )) {
691
721
//matches number with a unit, e.g. 12px, 15pt, 20mm, ...
692
722
$ spacingLineRule = \PhpOffice \PhpWord \SimpleType \LineSpacingRule::EXACT ;
693
723
$ spacing = Converter::cssToTwip ($ matches [1 ]);
694
- } elseif (preg_match ('/([0-9]+)%/ ' , $ cValue , $ matches )) {
724
+ } elseif (preg_match ('/([0-9]+)%/ ' , $ value , $ matches )) {
695
725
//matches percentages
696
726
$ spacingLineRule = \PhpOffice \PhpWord \SimpleType \LineSpacingRule::AUTO ;
697
727
//we are subtracting 1 line height because the Spacing writer is adding one line
@@ -700,72 +730,72 @@ protected static function parseStyle($attribute, $styles)
700
730
//any other, wich is a multiplier. E.g. 1.2
701
731
$ spacingLineRule = \PhpOffice \PhpWord \SimpleType \LineSpacingRule::AUTO ;
702
732
//we are subtracting 1 line height because the Spacing writer is adding one line
703
- $ spacing = ($ cValue * Paragraph::LINE_HEIGHT ) - Paragraph::LINE_HEIGHT ;
733
+ $ spacing = ($ value * Paragraph::LINE_HEIGHT ) - Paragraph::LINE_HEIGHT ;
704
734
}
705
735
$ styles ['spacingLineRule ' ] = $ spacingLineRule ;
706
736
$ styles ['line-spacing ' ] = $ spacing ;
707
737
708
738
break ;
709
739
case 'letter-spacing ' :
710
- $ styles ['letter-spacing ' ] = Converter::cssToTwip ($ cValue );
740
+ $ styles ['letter-spacing ' ] = Converter::cssToTwip ($ value );
711
741
712
742
break ;
713
743
case 'text-indent ' :
714
- $ styles ['indentation ' ]['firstLine ' ] = Converter::cssToTwip ($ cValue );
744
+ $ styles ['indentation ' ]['firstLine ' ] = Converter::cssToTwip ($ value );
715
745
716
746
break ;
717
747
case 'font-weight ' :
718
748
$ tValue = false ;
719
- if (preg_match ('#bold# ' , $ cValue )) {
749
+ if (preg_match ('#bold# ' , $ value )) {
720
750
$ tValue = true ; // also match bolder
721
751
}
722
752
$ styles ['bold ' ] = $ tValue ;
723
753
724
754
break ;
725
755
case 'font-style ' :
726
756
$ tValue = false ;
727
- if (preg_match ('#(?:italic|oblique)# ' , $ cValue )) {
757
+ if (preg_match ('#(?:italic|oblique)# ' , $ value )) {
728
758
$ tValue = true ;
729
759
}
730
760
$ styles ['italic ' ] = $ tValue ;
731
761
732
762
break ;
733
763
case 'margin ' :
734
- $ cValue = Converter::cssToTwip ($ cValue );
735
- $ styles ['spaceBefore ' ] = $ cValue ;
736
- $ styles ['spaceAfter ' ] = $ cValue ;
764
+ $ value = Converter::cssToTwip ($ value );
765
+ $ styles ['spaceBefore ' ] = $ value ;
766
+ $ styles ['spaceAfter ' ] = $ value ;
737
767
738
768
break ;
739
769
case 'margin-top ' :
740
- // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($cValue )
741
- $ styles ['spaceBefore ' ] = Converter::cssToTwip ($ cValue );
770
+ // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($value )
771
+ $ styles ['spaceBefore ' ] = Converter::cssToTwip ($ value );
742
772
743
773
break ;
744
774
case 'margin-bottom ' :
745
- // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($cValue )
746
- $ styles ['spaceAfter ' ] = Converter::cssToTwip ($ cValue );
775
+ // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($value )
776
+ $ styles ['spaceAfter ' ] = Converter::cssToTwip ($ value );
747
777
748
778
break ;
749
779
case 'border-color ' :
750
- self ::mapBorderColor ($ styles , $ cValue );
780
+ self ::mapBorderColor ($ styles , $ value );
751
781
752
782
break ;
753
783
case 'border-width ' :
754
- $ styles ['borderSize ' ] = Converter::cssToPoint ($ cValue );
784
+ $ styles ['borderSize ' ] = Converter::cssToPoint ($ value );
755
785
756
786
break ;
757
787
case 'border-style ' :
758
- $ styles ['borderStyle ' ] = self ::mapBorderStyle ($ cValue );
788
+ $ styles ['borderStyle ' ] = self ::mapBorderStyle ($ value );
759
789
760
790
break ;
761
791
case 'width ' :
762
- if (preg_match ('/([0-9]+[a-z]+)/ ' , $ cValue , $ matches )) {
792
+ if (preg_match ('/([0-9]+[a-z]+)/ ' , $ value , $ matches )) {
763
793
$ styles ['width ' ] = Converter::cssToTwip ($ matches [1 ]);
764
794
$ styles ['unit ' ] = \PhpOffice \PhpWord \SimpleType \TblWidth::TWIP ;
765
- } elseif (preg_match ('/([0-9]+)%/ ' , $ cValue , $ matches )) {
795
+ } elseif (preg_match ('/([0-9]+)%/ ' , $ value , $ matches )) {
766
796
$ styles ['width ' ] = $ matches [1 ] * 50 ;
767
797
$ styles ['unit ' ] = \PhpOffice \PhpWord \SimpleType \TblWidth::PERCENT ;
768
- } elseif (preg_match ('/([0-9]+)/ ' , $ cValue , $ matches )) {
798
+ } elseif (preg_match ('/([0-9]+)/ ' , $ value , $ matches )) {
769
799
$ styles ['width ' ] = $ matches [1 ];
770
800
$ styles ['unit ' ] = \PhpOffice \PhpWord \SimpleType \TblWidth::AUTO ;
771
801
}
@@ -778,9 +808,9 @@ protected static function parseStyle($attribute, $styles)
778
808
case 'border-left ' :
779
809
// must have exact order [width color style], e.g. "1px #0011CC solid" or "2pt green solid"
780
810
// Word does not accept shortened hex colors e.g. #CCC, only full e.g. #CCCCCC
781
- if (preg_match ('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+|[a-zA-Z]+)\s+([a-z]+)/ ' , $ cValue , $ matches )) {
782
- if (false !== strpos ($ cKey , '- ' )) {
783
- $ tmp = explode ('- ' , $ cKey );
811
+ if (preg_match ('/([0-9]+[^0-9]*)\s+(\#[a-fA-F0-9]+|[a-zA-Z]+)\s+([a-z]+)/ ' , $ value , $ matches )) {
812
+ if (false !== strpos ($ property , '- ' )) {
813
+ $ tmp = explode ('- ' , $ property );
784
814
$ which = $ tmp [1 ];
785
815
$ which = ucfirst ($ which ); // e.g. bottom -> Bottom
786
816
} else {
@@ -803,13 +833,13 @@ protected static function parseStyle($attribute, $styles)
803
833
break ;
804
834
case 'vertical-align ' :
805
835
// https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align
806
- if (preg_match ('#(?:top|bottom|middle|sub|baseline)#i ' , $ cValue , $ matches )) {
836
+ if (preg_match ('#(?:top|bottom|middle|sub|baseline)#i ' , $ value , $ matches )) {
807
837
$ styles ['valign ' ] = self ::mapAlignVertical ($ matches [0 ]);
808
838
}
809
839
810
840
break ;
811
841
case 'page-break-after ' :
812
- if ($ cValue == 'always ' ) {
842
+ if ($ value == 'always ' ) {
813
843
$ styles ['isPageBreak ' ] = true ;
814
844
}
815
845
0 commit comments