diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b331d6..62694eea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ v0.15.0 (?? ??? 2018) - Parsing of "align" HTML attribute - @troosan #1231 ### Fixed +- fix reading of docx default style - @troosan #1238 + + v0.14.0 (29 Dec 2017) ---------------------- @@ -58,6 +61,8 @@ This version brings compatibility with PHP 7.0 & 7.1 ### Deprecated - PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection(); + + v0.13.0 (31 July 2016) ------------------- This release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default). @@ -77,7 +82,7 @@ Manual installation feature has been dropped since the release. Please, use [Com - Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371 - Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko - Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617 -- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis +- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis ### Deprecated - `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles. diff --git a/docs/elements.rst b/docs/elements.rst index c73ffa06..94ff2667 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -160,7 +160,7 @@ Parameters: - ``$text``. Text that appears in the document. - ``$depth``. Depth of list item. - ``$fontStyle``. See :ref:`font-style`. -- ``$listStyle``. List style of the current element TYPE\_NUMBER, +- ``$listStyle``. List style of the current element TYPE\_NUMBER, TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\\Style\\ListItem. - ``$paragraphStyle``. See :ref:`paragraph-style`. @@ -345,7 +345,7 @@ The footnote numbering can be controlled by setting the FootnoteProperties on th .. code-block:: php $fp = new PhpWord\SimpleType\FootnoteProperties(); - //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) + //sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd) $fp->setPos(FootnoteProperties::POSITION_DOC_END); //set the number format to use (decimal (default), upperRoman, upperLetter, ...) $fp->setNumFmt(FootnoteProperties::NUMBER_FORMAT_LOWER_ROMAN); @@ -353,7 +353,6 @@ The footnote numbering can be controlled by setting the FootnoteProperties on th $fp->setNumStart(2); //when to restart counting (continuous (default), eachSect, eachPage) $fp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE); - //And finaly, set it on the Section $section->setFootnoteProperties($properties); @@ -379,7 +378,7 @@ To be completed Fields ------ -Currently the following fields are supported: +Currently the following fields are supported: - PAGE - NUMPAGES diff --git a/docs/general.rst b/docs/general.rst index ae090f2d..09a23cee 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -167,7 +167,6 @@ Use mirror margins to set up facing pages for double-sided documents, such as bo $phpWord->getSettings()->setMirrorMargins(true); - Spelling and grammatical checks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -191,7 +190,7 @@ You can also specify the status of the spell and grammar checks, marking spellin Track Revisions ~~~~~~~~~~~~~~~ -Track changes can be activated using ``setTrackRevisions``, you can furture specify +Track changes can be activated using ``setTrackRevisions``, you can furture specify - Not to use move syntax, instead moved items will be seen as deleted in one place and added in another - Not track formatting revisions diff --git a/docs/installing.rst b/docs/installing.rst index 37e4d379..4f407f54 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -51,7 +51,6 @@ Example: } } - Using samples ------------- diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 6a48fd46..3d853e8f 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -307,7 +307,7 @@ abstract class AbstractPart $styleNode = $xmlReader->getElement('w:pPr', $domNode); $styleDefs = array( - 'styleName' => array(self::READ_VALUE, 'w:pStyle'), + 'styleName' => array(self::READ_VALUE, array('w:pStyle', 'w:name')), 'alignment' => array(self::READ_VALUE, 'w:jc'), 'basedOn' => array(self::READ_VALUE, 'w:basedOn'), 'next' => array(self::READ_VALUE, 'w:next'), @@ -349,9 +349,9 @@ abstract class AbstractPart $styleNode = $xmlReader->getElement('w:rPr', $domNode); $styleDefs = array( 'styleName' => array(self::READ_VALUE, 'w:rStyle'), - 'name' => array(self::READ_VALUE, 'w:rFonts', 'w:ascii'), + 'name' => array(self::READ_VALUE, 'w:rFonts', array('w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs')), 'hint' => array(self::READ_VALUE, 'w:rFonts', 'w:hint'), - 'size' => array(self::READ_SIZE, 'w:sz'), + 'size' => array(self::READ_SIZE, array('w:sz', 'w:szCs')), 'color' => array(self::READ_VALUE, 'w:color'), 'underline' => array(self::READ_VALUE, 'w:u'), 'bold' => array(self::READ_TRUE, 'w:b'), @@ -364,9 +364,7 @@ abstract class AbstractPart 'subScript' => array(self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'), 'fgColor' => array(self::READ_VALUE, 'w:highlight'), 'rtl' => array(self::READ_TRUE, 'w:rtl'), - 'font-latin' => array(self::READ_VALUE, 'w:font', 'w:val'), - 'font-eastAsia' => array(self::READ_VALUE, 'w:font', 'w:eastAsia'), - 'font-bidi' => array(self::READ_VALUE, 'w:font', 'w:bidi'), + 'lang' => array(self::READ_VALUE, 'w:lang'), ); return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); @@ -400,6 +398,7 @@ abstract class AbstractPart $ucfSide = ucfirst($side); $styleDefs["border{$ucfSide}Size"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:sz'); $styleDefs["border{$ucfSide}Color"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:color'); + $styleDefs["border{$ucfSide}Style"] = array(self::READ_VALUE, "w:tblBorders/w:$side", 'w:val'); } $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs); } @@ -428,6 +427,54 @@ abstract class AbstractPart return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); } + /** + * Returns the first child element found + * + * @param XMLReader $xmlReader + * @param \DOMElement $parentNode + * @param string|array $elements + * @return string|null + */ + private function findPossibleElement(XMLReader $xmlReader, \DOMElement $parentNode = null, $elements) + { + if (is_array($elements)) { + //if element is an array, we take the first element that exists in the XML + foreach ($elements as $possibleElement) { + if ($xmlReader->elementExists($possibleElement, $parentNode)) { + return $possibleElement; + } + } + } else { + return $elements; + } + + return null; + } + + /** + * Returns the first attribute found + * + * @param XMLReader $xmlReader + * @param \DOMElement $node + * @param string|array $attributes + * @return string|null + */ + private function findPossibleAttribute(XMLReader $xmlReader, \DOMElement $node, $attributes) + { + //if attribute is an array, we take the first attribute that exists in the XML + if (is_array($attributes)) { + foreach ($attributes as $possibleAttribute) { + if ($xmlReader->getAttribute($possibleAttribute, $node)) { + return $possibleAttribute; + } + } + } else { + return $attributes; + } + + return null; + } + /** * Read style definition * @@ -442,11 +489,18 @@ abstract class AbstractPart $styles = array(); foreach ($styleDefs as $styleProp => $styleVal) { - @list($method, $element, $attribute, $expected) = $styleVal; + list($method, $element, $attribute, $expected) = array_pad($styleVal, 4, null); + + $element = $this->findPossibleElement($xmlReader, $parentNode, $element); + if ($element === null) { + continue; + } if ($xmlReader->elementExists($element, $parentNode)) { $node = $xmlReader->getElement($element, $parentNode); + $attribute = $this->findPossibleAttribute($xmlReader, $node, $attribute); + // Use w:val as default if no attribute assigned $attribute = ($attribute === null) ? 'w:val' : $attribute; $attributeValue = $xmlReader->getAttribute($attribute, $node); diff --git a/src/PhpWord/Reader/Word2007/Settings.php b/src/PhpWord/Reader/Word2007/Settings.php index ccdbed25..581a546d 100644 --- a/src/PhpWord/Reader/Word2007/Settings.php +++ b/src/PhpWord/Reader/Word2007/Settings.php @@ -80,8 +80,8 @@ class Settings extends AbstractPart $themeFontLang = new Language(); $themeFontLang->setLatin($val); - $themeFontLang->setLatin($eastAsia); - $themeFontLang->setLatin($bidi); + $themeFontLang->setEastAsia($eastAsia); + $themeFontLang->setBidirectional($bidi); $phpWord->getSettings()->setThemeFontLang($themeFontLang); } diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php index b8e6f22b..c6e64e45 100644 --- a/src/PhpWord/Reader/Word2007/Styles.php +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style\Language; /** * Styles reader @@ -37,6 +38,28 @@ class Styles extends AbstractPart $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); + $fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault'); + if ($fontDefaults !== null) { + $fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults); + if (array_key_exists('name', $fontDefaultStyle)) { + $phpWord->setDefaultFontName($fontDefaultStyle['name']); + } + if (array_key_exists('size', $fontDefaultStyle)) { + $phpWord->setDefaultFontSize($fontDefaultStyle['size']); + } + if (array_key_exists('lang', $fontDefaultStyle)) { + $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); + } + } + + $paragraphDefaults = $xmlReader->getElement('w:docDefaults/w:pPrDefault'); + if ($paragraphDefaults !== null) { + $paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults); + if ($paragraphDefaultStyle != null) { + $phpWord->setDefaultParagraphStyle(); + } + } + $nodes = $xmlReader->getElements('w:style'); if ($nodes->length > 0) { foreach ($nodes as $node) { diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c00dc97c..7e40d9e4 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -20,7 +20,6 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\Common\Text; use PhpOffice\PhpWord\Exception\InvalidStyleException; use PhpOffice\PhpWord\SimpleType\Jc; -use PhpOffice\PhpWord\SimpleType\LineSpacingRule; use PhpOffice\PhpWord\SimpleType\TextAlignment; /** diff --git a/src/PhpWord/Writer/Word2007/Element/Shape.php b/src/PhpWord/Writer/Word2007/Element/Shape.php index e384db06..9f111293 100644 --- a/src/PhpWord/Writer/Word2007/Element/Shape.php +++ b/src/PhpWord/Writer/Word2007/Element/Shape.php @@ -154,12 +154,12 @@ class Shape extends AbstractElement case 'arc': case 'line': $points = explode(' ', $value); - @list($start, $end) = $points; + list($start, $end) = array_pad($points, 2, null); $points = array('start' => $start, 'end' => $end); break; case 'curve': $points = explode(' ', $value); - @list($start, $end, $point1, $point2) = $points; + list($start, $end, $point1, $point2) = array_pad($points, 4, null); $points = array('start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2); break; } diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 126cda4f..1cc94806 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -18,7 +18,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\Common\XMLWriter; -use PhpOffice\PhpWord\Settings as PhpWordSettings; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font as FontStyle; use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle; @@ -82,9 +81,10 @@ class Styles extends AbstractPart */ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { - $fontName = PhpWordSettings::getDefaultFontName(); - $fontSize = PhpWordSettings::getDefaultFontSize(); - $language = $this->getParentWriter()->getPhpWord()->getSettings()->getThemeFontLang(); + $phpWord = $this->getParentWriter()->getPhpWord(); + $fontName = $phpWord->getDefaultFontName(); + $fontSize = $phpWord->getDefaultFontSize(); + $language = $phpWord->getSettings()->getThemeFontLang(); $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); // Default font @@ -123,7 +123,18 @@ class Styles extends AbstractPart $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); // w:name if (isset($styles['Normal'])) { - $styleWriter = new ParagraphStyleWriter($xmlWriter, $styles['Normal']); + $normalStyle = $styles['Normal']; + // w:pPr + if ($normalStyle instanceof Fontstyle && $normalStyle->getParagraph() != null) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle->getParagraph()); + $styleWriter->write(); + } elseif ($normalStyle instanceof ParagraphStyle) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle); + $styleWriter->write(); + } + + // w:rPr + $styleWriter = new FontStyleWriter($xmlWriter, $normalStyle); $styleWriter->write(); } $xmlWriter->endElement(); // w:style diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php index 424b87f8..8915fb4c 100644 --- a/src/PhpWord/Writer/Word2007/Style/Paragraph.php +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -109,7 +109,7 @@ class Paragraph extends AbstractStyle //Paragraph contextualSpacing $xmlWriter->writeElementIf($styles['contextualSpacing'] === true, 'w:contextualSpacing'); - //Paragraph contextualSpacing + //Paragraph textAlignment $xmlWriter->writeElementIf($styles['textAlignment'] !== null, 'w:textAlignment', 'w:val', $styles['textAlignment']); // Child style: alignment, indentation, spacing, and shading