Merge branch 'develop' into various_html_parsing_fixes
This commit is contained in:
commit
5b381bc0c0
|
|
@ -9,6 +9,7 @@ v0.15.0 (?? ??? 2018)
|
||||||
- Parsing of "align" HTML attribute - @troosan #1231
|
- Parsing of "align" HTML attribute - @troosan #1231
|
||||||
- Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508
|
- Parse formatting inside HTML lists - @troosan @samimussbach #1239 #945 #1215 #508
|
||||||
- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254
|
- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell - @troosan #1273 #1252 #1254
|
||||||
|
- Add support for Track changes @Cip @troosan #354 #1262
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- fix reading of docx default style - @troosan #1238
|
- fix reading of docx default style - @troosan #1238
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ column shows the containers while the rows lists the elements.
|
||||||
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
||||||
| 11 | Watermark | - | v | - | - | - | - |
|
| 11 | Watermark | - | v | - | - | - | - |
|
||||||
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
||||||
| 12 | Object | v | v | v | v | v | v |
|
| 12 | OLEObject | v | v | v | v | v | v |
|
||||||
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
||||||
| 13 | TOC | v | - | - | - | - | - |
|
| 13 | TOC | v | - | - | - | - | - |
|
||||||
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
+-------+-----------------+-----------+----------+----------+---------+------------+------------+
|
||||||
|
|
@ -77,6 +77,13 @@ italics, etc) or other elements, e.g. images or links. The syntaxes are as follo
|
||||||
|
|
||||||
For available styling options see :ref:`font-style` and :ref:`paragraph-style`.
|
For available styling options see :ref:`font-style` and :ref:`paragraph-style`.
|
||||||
|
|
||||||
|
If you want to enable track changes on added text you can mark it as INSERTED or DELETED by a specific user at a given time:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
$text = $section->addText('Hello World!');
|
||||||
|
$text->setChanged(\PhpOffice\PhpWord\Element\ChangedElement::TYPE_INSERTED, 'Fred', (new \DateTime()));
|
||||||
|
|
||||||
Titles
|
Titles
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
|
|
@ -276,11 +283,11 @@ Objects
|
||||||
-------
|
-------
|
||||||
|
|
||||||
You can add OLE embeddings, such as Excel spreadsheets or PowerPoint
|
You can add OLE embeddings, such as Excel spreadsheets or PowerPoint
|
||||||
presentations to the document by using ``addObject`` method.
|
presentations to the document by using ``addOLEObject`` method.
|
||||||
|
|
||||||
.. code-block:: php
|
.. code-block:: php
|
||||||
|
|
||||||
$section->addObject($src, [$style]);
|
$section->addOLEObject($src, [$style]);
|
||||||
|
|
||||||
Table of contents
|
Table of contents
|
||||||
-----------------
|
-----------------
|
||||||
|
|
@ -309,7 +316,7 @@ Footnotes & endnotes
|
||||||
You can create footnotes with ``addFootnote`` and endnotes with
|
You can create footnotes with ``addFootnote`` and endnotes with
|
||||||
``addEndnote`` in texts or textruns, but it's recommended to use textrun
|
``addEndnote`` in texts or textruns, but it's recommended to use textrun
|
||||||
to have better layout. You can use ``addText``, ``addLink``,
|
to have better layout. You can use ``addText``, ``addLink``,
|
||||||
``addTextBreak``, ``addImage``, ``addObject`` on footnotes and endnotes.
|
``addTextBreak``, ``addImage``, ``addOLEObject`` on footnotes and endnotes.
|
||||||
|
|
||||||
On textrun:
|
On textrun:
|
||||||
|
|
||||||
|
|
@ -466,3 +473,27 @@ The comment can contain formatted text. Once the comment has been added, it can
|
||||||
$text->setCommentStart($comment);
|
$text->setCommentStart($comment);
|
||||||
|
|
||||||
If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on.
|
If no end is set for a comment using the ``setCommentEnd``, the comment will be ended automatically at the end of the element it is started on.
|
||||||
|
|
||||||
|
Track Changes
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Track changes can be set on text elements. There are 2 ways to set the change information on an element.
|
||||||
|
Either by calling the `setChangeInfo()`, or by setting the `TrackChange` instance on the element with `setTrackChange()`.
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||||
|
|
||||||
|
// New portrait section
|
||||||
|
$section = $phpWord->addSection();
|
||||||
|
$textRun = $section->addTextRun();
|
||||||
|
|
||||||
|
$text = $textRun->addText('Hello World! Time to ');
|
||||||
|
|
||||||
|
$text = $textRun->addText('wake ', array('bold' => true));
|
||||||
|
$text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800);
|
||||||
|
|
||||||
|
$text = $textRun->addText('up');
|
||||||
|
$text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred'));
|
||||||
|
|
||||||
|
$text = $textRun->addText('go to sleep');
|
||||||
|
$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600)));
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||||
$section = $phpWord->addSection();
|
$section = $phpWord->addSection();
|
||||||
$section->addText('You can open this OLE object by double clicking on the icon:');
|
$section->addText('You can open this OLE object by double clicking on the icon:');
|
||||||
$section->addTextBreak(2);
|
$section->addTextBreak(2);
|
||||||
$section->addObject('resources/_sheet.xls');
|
$section->addOLEObject('resources/_sheet.xls');
|
||||||
|
|
||||||
// Save file
|
// Save file
|
||||||
echo write($phpWord, basename(__FILE__, '.php'), $writers);
|
echo write($phpWord, basename(__FILE__, '.php'), $writers);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
|
|
||||||
|
include_once 'Sample_Header.php';
|
||||||
|
|
||||||
|
// New Word Document
|
||||||
|
echo date('H:i:s') , ' Create new PhpWord object' , EOL;
|
||||||
|
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||||
|
|
||||||
|
// New portrait section
|
||||||
|
$section = $phpWord->addSection();
|
||||||
|
$textRun = $section->addTextRun();
|
||||||
|
|
||||||
|
$text = $textRun->addText('Hello World! Time to ');
|
||||||
|
|
||||||
|
$text = $textRun->addText('wake ', array('bold' => true));
|
||||||
|
$text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800);
|
||||||
|
|
||||||
|
$text = $textRun->addText('up');
|
||||||
|
$text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred'));
|
||||||
|
|
||||||
|
$text = $textRun->addText('go to sleep');
|
||||||
|
$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600)));
|
||||||
|
|
||||||
|
// Save file
|
||||||
|
echo write($phpWord, basename(__FILE__, '.php'), $writers);
|
||||||
|
if (!CLI) {
|
||||||
|
include_once 'Sample_Footer.php';
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -81,7 +81,7 @@ abstract class AbstractContainer extends AbstractElement
|
||||||
{
|
{
|
||||||
$elements = array(
|
$elements = array(
|
||||||
'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak',
|
'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak',
|
||||||
'ListItem', 'ListItemRun', 'Table', 'Image', 'Object',
|
'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'OLEObject',
|
||||||
'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
|
'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
|
||||||
'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
|
'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
|
||||||
'Chart', 'FormField', 'SDT', 'Comment',
|
'Chart', 'FormField', 'SDT', 'Comment',
|
||||||
|
|
@ -157,7 +157,7 @@ abstract class AbstractContainer extends AbstractElement
|
||||||
/**
|
/**
|
||||||
* Get all elements
|
* Get all elements
|
||||||
*
|
*
|
||||||
* @return array
|
* @return \PhpOffice\PhpWord\Element\AbstractElement[]
|
||||||
*/
|
*/
|
||||||
public function getElements()
|
public function getElements()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,13 @@ abstract class AbstractElement
|
||||||
*/
|
*/
|
||||||
private $parent;
|
private $parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* changed element info
|
||||||
|
*
|
||||||
|
* @var TrackChange
|
||||||
|
*/
|
||||||
|
private $trackChange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parent container type
|
* Parent container type
|
||||||
*
|
*
|
||||||
|
|
@ -438,6 +445,38 @@ abstract class AbstractElement
|
||||||
return $style;
|
return $style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the trackChange information
|
||||||
|
*
|
||||||
|
* @param TrackChange $trackChange
|
||||||
|
*/
|
||||||
|
public function setTrackChange(TrackChange $trackChange)
|
||||||
|
{
|
||||||
|
$this->trackChange = $trackChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the trackChange information
|
||||||
|
*
|
||||||
|
* @return TrackChange
|
||||||
|
*/
|
||||||
|
public function getTrackChange()
|
||||||
|
{
|
||||||
|
return $this->trackChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set changed
|
||||||
|
*
|
||||||
|
* @param string $type INSERTED|DELETED
|
||||||
|
* @param string $author
|
||||||
|
* @param null|int|\DateTime $date allways in UTC
|
||||||
|
*/
|
||||||
|
public function setChangeInfo($type, $author, $date = null)
|
||||||
|
{
|
||||||
|
$this->trackChange = new TrackChange($type, $author, $date);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set enum value
|
* Set enum value
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -55,12 +55,12 @@ class Comment extends TrackChange
|
||||||
* Create a new Comment Element
|
* Create a new Comment Element
|
||||||
*
|
*
|
||||||
* @param string $author
|
* @param string $author
|
||||||
* @param \DateTime $date
|
* @param null|\DateTime $date
|
||||||
* @param string $initials
|
* @param string $initials
|
||||||
*/
|
*/
|
||||||
public function __construct($author, $date = null, $initials = null)
|
public function __construct($author, $date = null, $initials = null)
|
||||||
{
|
{
|
||||||
parent::__construct($author, $date);
|
parent::__construct(null, $author, $date);
|
||||||
$this->initials = $initials;
|
$this->initials = $initials;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,10 @@ class Image extends AbstractElement
|
||||||
// Read image binary data and convert to hex/base64 string
|
// Read image binary data and convert to hex/base64 string
|
||||||
if ($this->sourceType == self::SOURCE_GD) {
|
if ($this->sourceType == self::SOURCE_GD) {
|
||||||
$imageResource = call_user_func($this->imageCreateFunc, $actualSource);
|
$imageResource = call_user_func($this->imageCreateFunc, $actualSource);
|
||||||
|
if ($this->imageType === 'image/png') {
|
||||||
|
// PNG images need to preserve alpha channel information
|
||||||
|
imagesavealpha($imageResource, true);
|
||||||
|
}
|
||||||
ob_start();
|
ob_start();
|
||||||
call_user_func($this->imageFunc, $imageResource);
|
call_user_func($this->imageFunc, $imageResource);
|
||||||
$imageBinary = ob_get_contents();
|
$imageBinary = ob_get_contents();
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,25 @@ namespace PhpOffice\PhpWord\Element;
|
||||||
/**
|
/**
|
||||||
* TrackChange element
|
* TrackChange element
|
||||||
* @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html
|
* @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html
|
||||||
|
* @see http://datypic.com/sc/ooxml/t-w_CT_RunTrackChange.html
|
||||||
*/
|
*/
|
||||||
class TrackChange extends AbstractContainer
|
class TrackChange extends AbstractContainer
|
||||||
{
|
{
|
||||||
|
const INSERTED = 'INSERTED';
|
||||||
|
const DELETED = 'DELETED';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string Container type
|
* @var string Container type
|
||||||
*/
|
*/
|
||||||
protected $container = 'TrackChange';
|
protected $container = 'TrackChange';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of change, (insert or delete), not applicable for PhpOffice\PhpWord\Element\Comment
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $changeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Author
|
* Author
|
||||||
*
|
*
|
||||||
|
|
@ -45,13 +56,17 @@ class TrackChange extends AbstractContainer
|
||||||
/**
|
/**
|
||||||
* Create a new TrackChange Element
|
* Create a new TrackChange Element
|
||||||
*
|
*
|
||||||
|
* @param string $changeType
|
||||||
* @param string $author
|
* @param string $author
|
||||||
* @param \DateTime $date
|
* @param null|int|\DateTime $date
|
||||||
*/
|
*/
|
||||||
public function __construct($author, \DateTime $date = null)
|
public function __construct($changeType = null, $author = null, $date = null)
|
||||||
{
|
{
|
||||||
|
$this->changeType = $changeType;
|
||||||
$this->author = $author;
|
$this->author = $author;
|
||||||
$this->date = $date;
|
if ($date !== null) {
|
||||||
|
$this->date = ($date instanceof \DateTime) ? $date : new \DateTime('@' . $date);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,4 +88,14 @@ class TrackChange extends AbstractContainer
|
||||||
{
|
{
|
||||||
return $this->date;
|
return $this->date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Change type
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getChangeType()
|
||||||
|
{
|
||||||
|
return $this->changeType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
namespace PhpOffice\PhpWord\Reader\ODText;
|
namespace PhpOffice\PhpWord\Reader\ODText;
|
||||||
|
|
||||||
use PhpOffice\Common\XMLReader;
|
use PhpOffice\Common\XMLReader;
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
use PhpOffice\PhpWord\PhpWord;
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,6 +38,8 @@ class Content extends AbstractPart
|
||||||
$xmlReader = new XMLReader();
|
$xmlReader = new XMLReader();
|
||||||
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
|
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
|
||||||
|
|
||||||
|
$trackedChanges = array();
|
||||||
|
|
||||||
$nodes = $xmlReader->getElements('office:body/office:text/*');
|
$nodes = $xmlReader->getElements('office:body/office:text/*');
|
||||||
if ($nodes->length > 0) {
|
if ($nodes->length > 0) {
|
||||||
$section = $phpWord->addSection();
|
$section = $phpWord->addSection();
|
||||||
|
|
@ -48,7 +51,37 @@ class Content extends AbstractPart
|
||||||
$section->addTitle($node->nodeValue, $depth);
|
$section->addTitle($node->nodeValue, $depth);
|
||||||
break;
|
break;
|
||||||
case 'text:p': // Paragraph
|
case 'text:p': // Paragraph
|
||||||
$section->addText($node->nodeValue);
|
$children = $node->childNodes;
|
||||||
|
foreach ($children as $child) {
|
||||||
|
switch ($child->nodeName) {
|
||||||
|
case 'text:change-start':
|
||||||
|
$changeId = $child->getAttribute('text:change-id');
|
||||||
|
if (isset($trackedChanges[$changeId])) {
|
||||||
|
$changed = $trackedChanges[$changeId];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'text:change-end':
|
||||||
|
unset($changed);
|
||||||
|
break;
|
||||||
|
case 'text:change':
|
||||||
|
$changeId = $child->getAttribute('text:change-id');
|
||||||
|
if (isset($trackedChanges[$changeId])) {
|
||||||
|
$changed = $trackedChanges[$changeId];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$element = $section->addText($node->nodeValue);
|
||||||
|
if (isset($changed) && is_array($changed)) {
|
||||||
|
$element->setTrackChange($changed['changed']);
|
||||||
|
if (isset($changed['textNodes'])) {
|
||||||
|
foreach ($changed['textNodes'] as $changedNode) {
|
||||||
|
$element = $section->addText($changedNode->nodeValue);
|
||||||
|
$element->setTrackChange($changed['changed']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'text:list': // List
|
case 'text:list': // List
|
||||||
$listItems = $xmlReader->getElements('text:list-item/text:p', $node);
|
$listItems = $xmlReader->getElements('text:list-item/text:p', $node);
|
||||||
|
|
@ -57,6 +90,21 @@ class Content extends AbstractPart
|
||||||
$section->addListItem($listItem->nodeValue, 0);
|
$section->addListItem($listItem->nodeValue, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'text:tracked-changes':
|
||||||
|
$changedRegions = $xmlReader->getElements('text:changed-region', $node);
|
||||||
|
foreach ($changedRegions as $changedRegion) {
|
||||||
|
$type = ($changedRegion->firstChild->nodeName == 'text:insertion') ? TrackChange::INSERTED : TrackChange::DELETED;
|
||||||
|
$creatorNode = $xmlReader->getElements('office:change-info/dc:creator', $changedRegion->firstChild);
|
||||||
|
$author = $creatorNode[0]->nodeValue;
|
||||||
|
$dateNode = $xmlReader->getElements('office:change-info/dc:date', $changedRegion->firstChild);
|
||||||
|
$date = $dateNode[0]->nodeValue;
|
||||||
|
$date = preg_replace('/\.\d+$/', '', $date);
|
||||||
|
$date = \DateTime::createFromFormat('Y-m-d\TH:i:s', $date);
|
||||||
|
$changed = new TrackChange($type, $author, $date);
|
||||||
|
$textNodes = $xmlReader->getElements('text:deletion/text:p', $changedRegion);
|
||||||
|
$trackedChanges[$changedRegion->getAttribute('text:id')] = array('changed' => $changed, 'textNodes'=> $textNodes);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
namespace PhpOffice\PhpWord\Reader\Word2007;
|
namespace PhpOffice\PhpWord\Reader\Word2007;
|
||||||
|
|
||||||
use PhpOffice\Common\XMLReader;
|
use PhpOffice\Common\XMLReader;
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
use PhpOffice\PhpWord\PhpWord;
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -156,8 +157,10 @@ abstract class AbstractPart
|
||||||
} else {
|
} else {
|
||||||
// Text and TextRun
|
// Text and TextRun
|
||||||
$runCount = $xmlReader->countElements('w:r', $domNode);
|
$runCount = $xmlReader->countElements('w:r', $domNode);
|
||||||
|
$insCount = $xmlReader->countElements('w:ins', $domNode);
|
||||||
|
$delCount = $xmlReader->countElements('w:del', $domNode);
|
||||||
$linkCount = $xmlReader->countElements('w:hyperlink', $domNode);
|
$linkCount = $xmlReader->countElements('w:hyperlink', $domNode);
|
||||||
$runLinkCount = $runCount + $linkCount;
|
$runLinkCount = $runCount + $insCount + $delCount + $linkCount;
|
||||||
if (0 == $runLinkCount) {
|
if (0 == $runLinkCount) {
|
||||||
$parent->addTextBreak(null, $paragraphStyle);
|
$parent->addTextBreak(null, $paragraphStyle);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -185,6 +188,13 @@ abstract class AbstractPart
|
||||||
*/
|
*/
|
||||||
protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart, $paragraphStyle = null)
|
protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, $parent, $docPart, $paragraphStyle = null)
|
||||||
{
|
{
|
||||||
|
if (in_array($domNode->nodeName, array('w:ins', 'w:del'))) {
|
||||||
|
$nodes = $xmlReader->getElements('*', $domNode);
|
||||||
|
foreach ($nodes as $node) {
|
||||||
|
return $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) {
|
if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -228,8 +238,19 @@ abstract class AbstractPart
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TextRun
|
// TextRun
|
||||||
$textContent = $xmlReader->getValue('w:t', $domNode);
|
if ($domNode->parentNode->nodeName == 'w:del') {
|
||||||
$parent->addText($textContent, $fontStyle, $paragraphStyle);
|
$textContent = $xmlReader->getValue('w:delText', $domNode);
|
||||||
|
} else {
|
||||||
|
$textContent = $xmlReader->getValue('w:t', $domNode);
|
||||||
|
}
|
||||||
|
/** @var AbstractElement $element */
|
||||||
|
$element = $parent->addText($textContent, $fontStyle, $paragraphStyle);
|
||||||
|
if (in_array($domNode->parentNode->nodeName, array('w:ins', 'w:del'))) {
|
||||||
|
$type = ($domNode->parentNode->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED;
|
||||||
|
$author = $domNode->parentNode->getAttribute('w:author');
|
||||||
|
$date = \DateTime::createFromFormat('Y-m-d\TH:i:s\Z', $domNode->parentNode->getAttribute('w:date'));
|
||||||
|
$element->setChangeInfo($type, $author, $date);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class Styles extends AbstractPart
|
||||||
if ($paragraphDefaults !== null) {
|
if ($paragraphDefaults !== null) {
|
||||||
$paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults);
|
$paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults);
|
||||||
if ($paragraphDefaultStyle != null) {
|
if ($paragraphDefaultStyle != null) {
|
||||||
$phpWord->setDefaultParagraphStyle();
|
$phpWord->setDefaultParagraphStyle($paragraphDefaultStyle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -352,6 +352,10 @@ abstract class AbstractWriter implements WriterInterface
|
||||||
// Retrive GD image content or get local media
|
// Retrive GD image content or get local media
|
||||||
if (isset($element['isMemImage']) && $element['isMemImage']) {
|
if (isset($element['isMemImage']) && $element['isMemImage']) {
|
||||||
$image = call_user_func($element['createFunction'], $element['source']);
|
$image = call_user_func($element['createFunction'], $element['source']);
|
||||||
|
if ($element['imageType'] === 'image/png') {
|
||||||
|
// PNG images need to preserve alpha channel information
|
||||||
|
imagesavealpha($image, true);
|
||||||
|
}
|
||||||
ob_start();
|
ob_start();
|
||||||
call_user_func($element['imageFunction'], $image);
|
call_user_func($element['imageFunction'], $image);
|
||||||
$imageContents = ob_get_contents();
|
$imageContents = ob_get_contents();
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer\HTML\Element;
|
namespace PhpOffice\PhpWord\Writer\HTML\Element;
|
||||||
|
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
use PhpOffice\PhpWord\Settings;
|
use PhpOffice\PhpWord\Settings;
|
||||||
use PhpOffice\PhpWord\Style\Font;
|
use PhpOffice\PhpWord\Style\Font;
|
||||||
use PhpOffice\PhpWord\Style\Paragraph;
|
use PhpOffice\PhpWord\Style\Paragraph;
|
||||||
|
|
@ -121,6 +122,9 @@ class Text extends AbstractElement
|
||||||
$content .= "<p{$style}>";
|
$content .= "<p{$style}>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//open track change tag
|
||||||
|
$content .= $this->writeTrackChangeOpening();
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,6 +136,10 @@ class Text extends AbstractElement
|
||||||
protected function writeClosing()
|
protected function writeClosing()
|
||||||
{
|
{
|
||||||
$content = '';
|
$content = '';
|
||||||
|
|
||||||
|
//close track change tag
|
||||||
|
$content .= $this->writeTrackChangeClosing();
|
||||||
|
|
||||||
if (!$this->withoutP) {
|
if (!$this->withoutP) {
|
||||||
if (Settings::isOutputEscapingEnabled()) {
|
if (Settings::isOutputEscapingEnabled()) {
|
||||||
$content .= $this->escaper->escapeHtml($this->closingText);
|
$content .= $this->escaper->escapeHtml($this->closingText);
|
||||||
|
|
@ -145,6 +153,63 @@ class Text extends AbstractElement
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* writes the track change opening tag
|
||||||
|
*
|
||||||
|
* @return string the HTML, an empty string if no track change information
|
||||||
|
*/
|
||||||
|
private function writeTrackChangeOpening()
|
||||||
|
{
|
||||||
|
$changed = $this->element->getTrackChange();
|
||||||
|
if ($changed == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = '';
|
||||||
|
if (($changed->getChangeType() == TrackChange::INSERTED)) {
|
||||||
|
$content .= '<ins data-phpword-prop=\'';
|
||||||
|
} elseif ($changed->getChangeType() == TrackChange::DELETED) {
|
||||||
|
$content .= '<del data-phpword-prop=\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
$changedProp = array('changed' => array('author'=> $changed->getAuthor(), 'id' => $this->element->getElementId()));
|
||||||
|
if ($changed->getDate() != null) {
|
||||||
|
$changedProp['changed']['date'] = $changed->getDate()->format('Y-m-d\TH:i:s\Z');
|
||||||
|
}
|
||||||
|
$content .= json_encode($changedProp);
|
||||||
|
$content .= '\' ';
|
||||||
|
$content .= 'title="' . $changed->getAuthor();
|
||||||
|
if ($changed->getDate() != null) {
|
||||||
|
$dateUser = $changed->getDate()->format('Y-m-d H:i:s');
|
||||||
|
$content .= ' - ' . $dateUser;
|
||||||
|
}
|
||||||
|
$content .= '">';
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* writes the track change closing tag
|
||||||
|
*
|
||||||
|
* @return string the HTML, an empty string if no track change information
|
||||||
|
*/
|
||||||
|
private function writeTrackChangeClosing()
|
||||||
|
{
|
||||||
|
$changed = $this->element->getTrackChange();
|
||||||
|
if ($changed == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = '';
|
||||||
|
if (($changed->getChangeType() == TrackChange::INSERTED)) {
|
||||||
|
$content .= '</ins>';
|
||||||
|
} elseif ($changed->getChangeType() == TrackChange::DELETED) {
|
||||||
|
$content .= '</del>';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write paragraph style
|
* Write paragraph style
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer\ODText\Element;
|
namespace PhpOffice\PhpWord\Writer\ODText\Element;
|
||||||
|
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
use PhpOffice\PhpWord\Exception\Exception;
|
use PhpOffice\PhpWord\Exception\Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -51,29 +52,50 @@ class Text extends AbstractElement
|
||||||
if (!$this->withoutP) {
|
if (!$this->withoutP) {
|
||||||
$xmlWriter->startElement('text:p'); // text:p
|
$xmlWriter->startElement('text:p'); // text:p
|
||||||
}
|
}
|
||||||
if (empty($fontStyle)) {
|
if ($element->getTrackChange() != null && $element->getTrackChange()->getChangeType() == TrackChange::DELETED) {
|
||||||
if (empty($paragraphStyle)) {
|
$xmlWriter->startElement('text:change');
|
||||||
$xmlWriter->writeAttribute('text:style-name', 'P1');
|
$xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId());
|
||||||
} elseif (is_string($paragraphStyle)) {
|
|
||||||
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
|
|
||||||
}
|
|
||||||
$this->writeText($element->getText());
|
|
||||||
} else {
|
|
||||||
if (empty($paragraphStyle)) {
|
|
||||||
$xmlWriter->writeAttribute('text:style-name', 'Standard');
|
|
||||||
} elseif (is_string($paragraphStyle)) {
|
|
||||||
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
|
|
||||||
}
|
|
||||||
// text:span
|
|
||||||
$xmlWriter->startElement('text:span');
|
|
||||||
if (is_string($fontStyle)) {
|
|
||||||
$xmlWriter->writeAttribute('text:style-name', $fontStyle);
|
|
||||||
}
|
|
||||||
$this->writeText($element->getText());
|
|
||||||
$xmlWriter->endElement();
|
$xmlWriter->endElement();
|
||||||
|
} else {
|
||||||
|
if (empty($fontStyle)) {
|
||||||
|
if (empty($paragraphStyle)) {
|
||||||
|
$xmlWriter->writeAttribute('text:style-name', 'P1');
|
||||||
|
} elseif (is_string($paragraphStyle)) {
|
||||||
|
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
|
||||||
|
}
|
||||||
|
$this->writeChangeInsertion(true, $element->getTrackChange());
|
||||||
|
$this->writeText($element->getText());
|
||||||
|
$this->writeChangeInsertion(false, $element->getTrackChange());
|
||||||
|
} else {
|
||||||
|
if (empty($paragraphStyle)) {
|
||||||
|
$xmlWriter->writeAttribute('text:style-name', 'Standard');
|
||||||
|
} elseif (is_string($paragraphStyle)) {
|
||||||
|
$xmlWriter->writeAttribute('text:style-name', $paragraphStyle);
|
||||||
|
}
|
||||||
|
// text:span
|
||||||
|
$xmlWriter->startElement('text:span');
|
||||||
|
if (is_string($fontStyle)) {
|
||||||
|
$xmlWriter->writeAttribute('text:style-name', $fontStyle);
|
||||||
|
}
|
||||||
|
$this->writeChangeInsertion(true, $element->getTrackChange());
|
||||||
|
$this->writeText($element->getText());
|
||||||
|
$this->writeChangeInsertion(false, $element->getTrackChange());
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!$this->withoutP) {
|
if (!$this->withoutP) {
|
||||||
$xmlWriter->endElement(); // text:p
|
$xmlWriter->endElement(); // text:p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function writeChangeInsertion($start = true, TrackChange $trackChange = null)
|
||||||
|
{
|
||||||
|
if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$xmlWriter = $this->getXmlWriter();
|
||||||
|
$xmlWriter->startElement('text:change-' . ($start ? 'start' : 'end'));
|
||||||
|
$xmlWriter->writeAttribute('text:change-id', $trackChange->getElementId());
|
||||||
|
$xmlWriter->endElement();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,12 @@
|
||||||
namespace PhpOffice\PhpWord\Writer\ODText\Part;
|
namespace PhpOffice\PhpWord\Writer\ODText\Part;
|
||||||
|
|
||||||
use PhpOffice\Common\XMLWriter;
|
use PhpOffice\Common\XMLWriter;
|
||||||
|
use PhpOffice\PhpWord\Element\AbstractContainer;
|
||||||
use PhpOffice\PhpWord\Element\Image;
|
use PhpOffice\PhpWord\Element\Image;
|
||||||
use PhpOffice\PhpWord\Element\Table;
|
use PhpOffice\PhpWord\Element\Table;
|
||||||
use PhpOffice\PhpWord\Element\Text;
|
use PhpOffice\PhpWord\Element\Text;
|
||||||
use PhpOffice\PhpWord\Element\TextRun;
|
use PhpOffice\PhpWord\Element\TextRun;
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
use PhpOffice\PhpWord\PhpWord;
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
use PhpOffice\PhpWord\Style;
|
use PhpOffice\PhpWord\Style;
|
||||||
use PhpOffice\PhpWord\Style\Font;
|
use PhpOffice\PhpWord\Style\Font;
|
||||||
|
|
@ -74,6 +76,40 @@ class Content extends AbstractPart
|
||||||
$xmlWriter->startElement('office:body');
|
$xmlWriter->startElement('office:body');
|
||||||
$xmlWriter->startElement('office:text');
|
$xmlWriter->startElement('office:text');
|
||||||
|
|
||||||
|
// Tracked changes declarations
|
||||||
|
$trackedChanges = array();
|
||||||
|
$sections = $phpWord->getSections();
|
||||||
|
foreach ($sections as $section) {
|
||||||
|
$this->collectTrackedChanges($section, $trackedChanges);
|
||||||
|
}
|
||||||
|
$xmlWriter->startElement('text:tracked-changes');
|
||||||
|
foreach ($trackedChanges as $trackedElement) {
|
||||||
|
$trackedChange = $trackedElement->getTrackChange();
|
||||||
|
$xmlWriter->startElement('text:changed-region');
|
||||||
|
$trackedChange->setElementId();
|
||||||
|
$xmlWriter->writeAttribute('text:id', $trackedChange->getElementId());
|
||||||
|
|
||||||
|
if (($trackedChange->getChangeType() == TrackChange::INSERTED)) {
|
||||||
|
$xmlWriter->startElement('text:insertion');
|
||||||
|
} elseif ($trackedChange->getChangeType() == TrackChange::DELETED) {
|
||||||
|
$xmlWriter->startElement('text:deletion');
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlWriter->startElement('office:change-info');
|
||||||
|
$xmlWriter->writeElement('dc:creator', $trackedChange->getAuthor());
|
||||||
|
if ($trackedChange->getDate() != null) {
|
||||||
|
$xmlWriter->writeElement('dc:date', $trackedChange->getDate()->format('Y-m-d\TH:i:s\Z'));
|
||||||
|
}
|
||||||
|
$xmlWriter->endElement(); // office:change-info
|
||||||
|
if ($trackedChange->getChangeType() == TrackChange::DELETED) {
|
||||||
|
$xmlWriter->writeElement('text:p', $trackedElement->getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlWriter->endElement(); // text:insertion|text:deletion
|
||||||
|
$xmlWriter->endElement(); // text:changed-region
|
||||||
|
}
|
||||||
|
$xmlWriter->endElement(); // text:tracked-changes
|
||||||
|
|
||||||
// Sequence declarations
|
// Sequence declarations
|
||||||
$sequences = array('Illustration', 'Table', 'Text', 'Drawing');
|
$sequences = array('Illustration', 'Table', 'Text', 'Drawing');
|
||||||
$xmlWriter->startElement('text:sequence-decls');
|
$xmlWriter->startElement('text:sequence-decls');
|
||||||
|
|
@ -242,4 +278,23 @@ class Content extends AbstractPart
|
||||||
$element->setParagraphStyle("P{$paragraphStyleCount}");
|
$element->setParagraphStyle("P{$paragraphStyleCount}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all tracked changes
|
||||||
|
*
|
||||||
|
* @param AbstractContainer $container
|
||||||
|
* @param \PhpOffice\PhpWord\Element\AbstractElement[] $trackedChanges
|
||||||
|
*/
|
||||||
|
private function collectTrackedChanges(AbstractContainer $container, &$trackedChanges = array())
|
||||||
|
{
|
||||||
|
$elements = $container->getElements();
|
||||||
|
foreach ($elements as $element) {
|
||||||
|
if ($element->getTrackChange() != null) {
|
||||||
|
$trackedChanges[] = $element;
|
||||||
|
}
|
||||||
|
if (is_callable(array($element, 'getElements'))) {
|
||||||
|
$this->collectTrackedChanges($element, $trackedChanges);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer\Word2007\Element;
|
namespace PhpOffice\PhpWord\Writer\Word2007\Element;
|
||||||
|
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text element writer
|
* Text element writer
|
||||||
*
|
*
|
||||||
|
|
@ -37,16 +39,66 @@ class Text extends AbstractElement
|
||||||
|
|
||||||
$this->startElementP();
|
$this->startElementP();
|
||||||
|
|
||||||
|
$this->writeOpeningTrackChange();
|
||||||
|
|
||||||
$xmlWriter->startElement('w:r');
|
$xmlWriter->startElement('w:r');
|
||||||
|
|
||||||
$this->writeFontStyle();
|
$this->writeFontStyle();
|
||||||
|
|
||||||
$xmlWriter->startElement('w:t');
|
$textElement = 'w:t';
|
||||||
|
//'w:delText' in case of deleted text
|
||||||
|
$changed = $element->getTrackChange();
|
||||||
|
if ($changed != null && $changed->getChangeType() == TrackChange::DELETED) {
|
||||||
|
$textElement = 'w:delText';
|
||||||
|
}
|
||||||
|
$xmlWriter->startElement($textElement);
|
||||||
|
|
||||||
$xmlWriter->writeAttribute('xml:space', 'preserve');
|
$xmlWriter->writeAttribute('xml:space', 'preserve');
|
||||||
$this->writeText($this->getText($element->getText()));
|
$this->writeText($this->getText($element->getText()));
|
||||||
$xmlWriter->endElement();
|
$xmlWriter->endElement();
|
||||||
$xmlWriter->endElement(); // w:r
|
$xmlWriter->endElement(); // w:r
|
||||||
|
|
||||||
|
$this->writeClosingTrackChange();
|
||||||
|
|
||||||
$this->endElementP(); // w:p
|
$this->endElementP(); // w:p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write opening of changed element
|
||||||
|
*/
|
||||||
|
protected function writeOpeningTrackChange()
|
||||||
|
{
|
||||||
|
$changed = $this->getElement()->getTrackChange();
|
||||||
|
if ($changed == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlWriter = $this->getXmlWriter();
|
||||||
|
|
||||||
|
if (($changed->getChangeType() == TrackChange::INSERTED)) {
|
||||||
|
$xmlWriter->startElement('w:ins');
|
||||||
|
} elseif ($changed->getChangeType() == TrackChange::DELETED) {
|
||||||
|
$xmlWriter->startElement('w:del');
|
||||||
|
}
|
||||||
|
$xmlWriter->writeAttribute('w:author', $changed->getAuthor());
|
||||||
|
if ($changed->getDate() != null) {
|
||||||
|
$xmlWriter->writeAttribute('w:date', $changed->getDate()->format('Y-m-d\TH:i:s\Z'));
|
||||||
|
}
|
||||||
|
$xmlWriter->writeAttribute('w:id', $this->getElement()->getElementId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write ending
|
||||||
|
*/
|
||||||
|
protected function writeClosingTrackChange()
|
||||||
|
{
|
||||||
|
$changed = $this->getElement()->getTrackChange();
|
||||||
|
if ($changed == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlWriter = $this->getXmlWriter();
|
||||||
|
|
||||||
|
$xmlWriter->endElement(); // w:ins|w:del
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
|
* word processing documents.
|
||||||
|
*
|
||||||
|
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||||
|
* General Public License version 3 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please read the LICENSE
|
||||||
|
* file that was distributed with this source code. For the full list of
|
||||||
|
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||||
|
*
|
||||||
|
* @see https://github.com/PHPOffice/PHPWord
|
||||||
|
* @copyright 2010-2017 PHPWord contributors
|
||||||
|
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpWord\Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for PhpOffice\PhpWord\Element\TrackChange
|
||||||
|
*
|
||||||
|
* @runTestsInSeparateProcesses
|
||||||
|
*/
|
||||||
|
class TrackChangeTest extends \PHPUnit\Framework\TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* New instance
|
||||||
|
*/
|
||||||
|
public function testConstructDefault()
|
||||||
|
{
|
||||||
|
$author = 'Test User';
|
||||||
|
$date = new \DateTime('2000-01-01');
|
||||||
|
$oTrackChange = new TrackChange(TrackChange::INSERTED, $author, $date);
|
||||||
|
|
||||||
|
$oText = new Text('dummy text');
|
||||||
|
$oText->setTrackChange($oTrackChange);
|
||||||
|
|
||||||
|
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TrackChange', $oTrackChange);
|
||||||
|
$this->assertEquals($author, $oTrackChange->getAuthor());
|
||||||
|
$this->assertEquals($date, $oTrackChange->getDate());
|
||||||
|
$this->assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,8 +19,8 @@ namespace PhpOffice\PhpWord\Writer\Word2007;
|
||||||
|
|
||||||
use PhpOffice\Common\XMLWriter;
|
use PhpOffice\Common\XMLWriter;
|
||||||
use PhpOffice\PhpWord\Element\Comment;
|
use PhpOffice\PhpWord\Element\Comment;
|
||||||
use PhpOffice\PhpWord\Element\Text;
|
|
||||||
use PhpOffice\PhpWord\Element\TextRun;
|
use PhpOffice\PhpWord\Element\TextRun;
|
||||||
|
use PhpOffice\PhpWord\Element\TrackChange;
|
||||||
use PhpOffice\PhpWord\PhpWord;
|
use PhpOffice\PhpWord\PhpWord;
|
||||||
use PhpOffice\PhpWord\TestHelperDOCX;
|
use PhpOffice\PhpWord\TestHelperDOCX;
|
||||||
|
|
||||||
|
|
@ -415,4 +415,20 @@ class ElementTest extends \PHPUnit\Framework\TestCase
|
||||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));
|
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));
|
||||||
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));
|
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTrackChange()
|
||||||
|
{
|
||||||
|
$phpWord = new PhpWord();
|
||||||
|
$section = $phpWord->addSection();
|
||||||
|
$text = $section->addText('my dummy text');
|
||||||
|
$text->setChangeInfo(TrackChange::INSERTED, 'author name');
|
||||||
|
$text2 = $section->addText('my other text');
|
||||||
|
$text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new \DateTime()));
|
||||||
|
|
||||||
|
$doc = TestHelperDOCX::getDocument($phpWord);
|
||||||
|
|
||||||
|
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:ins/w:r'));
|
||||||
|
$this->assertEquals('author name', $doc->getElementAttribute('/w:document/w:body/w:p/w:ins', 'w:author'));
|
||||||
|
$this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue