Update Posts transformer to extract images by splitting the DOM tree

This commit is contained in:
Tautvidas Sipavičius
2017-07-28 14:36:12 +03:00
parent 60b3c066a5
commit 6de746162e
4 changed files with 105 additions and 12 deletions

View File

@ -2,6 +2,7 @@
namespace MailPoet\Newsletter\Editor;
use pQuery;
use MailPoet\Util\DOM as DOMUtil;
if(!defined('ABSPATH')) exit;
@ -17,29 +18,22 @@ class StructureTransformer {
}
/**
* Hoists images to root level, preserves order
* and inserts tags before top ancestor
* Hoists images to root level, preserves order by splitting neighboring
* elements and inserts tags as children of top ancestor
*/
private function hoistImagesToRoot($root) {
protected function hoistImagesToRoot($root) {
foreach($root->query('img') as $item) {
$top_ancestor = $this->findTopAncestor($item);
$top_ancestor = DOMUtil::findTopAncestor($item);
$offset = $top_ancestor->index();
if($item->hasParent('a')) {
$item = $item->parent;
}
$item->changeParent($root, $offset);
DOMUtil::splitOn($item->getRoot(), $item);
}
}
private static function findTopAncestor($item) {
while($item->parent->parent !== null) {
$item = $item->parent;
}
return $item;
}
/**
* Transforms HTML tags into their respective JSON objects,
* turns other root children into text blocks

40
lib/Util/DOM.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace MailPoet\Util;
use pQuery\DomNode;
class DOM {
/**
* Splits a DOM tree around the cut element, bringing it up to bound
* ancestor and splitting left and right siblings into subtrees along
* the way, retaining order and nesting level.
*/
static function splitOn(DomNode $bound, DomNode $cut_element) {
$ignore_text_and_comment_nodes = false;
for($parent = $cut_element->parent; $bound != $parent; $parent = $grandparent) {
// Clone parent node without children, but with attributes
$parent->after($parent->toString());
$right = $parent->getNextSibling($ignore_text_and_comment_nodes);
$right->clear();
while($sibling = $cut_element->getNextSibling($ignore_text_and_comment_nodes)) {
$sibling->move($right);
}
// Reattach cut_element and right siblings to grandparent
$grandparent = $parent->parent;
$index_after_parent = $parent->index() + 1;
$right->move($grandparent, $index_after_parent);
$index_after_parent = $parent->index() + 1;
$cut_element->move($grandparent, $index_after_parent);
}
}
static function findTopAncestor(DomNode $item) {
while($item->parent->parent !== null) {
$item = $item->parent;
}
return $item;
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace MailPoet\Test\Newsletter\Editor;
use pQuery;
use MailPoet\Newsletter\Editor\StructureTransformer;
class StructureTransformerTest extends \MailPoetTest {
function _before() {
$this->transformer = new StructureTransformer();
}
function testItExtractsImagesAsImageBlocks() {
$html = '<p><i>italic</i><em>previous text<a href="#mylink"><img src="#myimage" /></a>next text</em><b>bolded</b></p>';
$blocks = $this->transformer->transform($html, false);
expect($blocks)->count(3);
expect($blocks[0]['type'])->equals('text');
expect($blocks[0]['text'])->equals('<p><i>italic</i><em>previous text</em></p>');
expect($blocks[1]['type'])->equals('image');
expect($blocks[1]['src'])->equals('#myimage');
expect($blocks[1]['link'])->equals('#mylink');
expect($blocks[2]['type'])->equals('text');
expect($blocks[2]['text'])->equals('<p><em>next text</em><b>bolded</b></p>');
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace MailPoet\Test\Util;
use pQuery;
use MailPoet\Util\DOM as DOMUtil;
class DOMTest extends \MailPoetTest {
function _before() {
$this->root = pQuery::parseStr('<p><i>italic</i><em>previous text<a href="#mylink"><img src="#myimage" /></a>next text</em><b>bolded</b></p>');
}
function testItDeepSplitsDOMTreeByElement() {
DOMUtil::splitOn($this->root, $this->root->query('a')->offsetGet(0));
expect($this->root->html())->equals(
'<p><i>italic</i><em>previous text</em></p>'.
'<a href="#mylink"><img src="#myimage" /></a>'.
'<p><em>next text</em><b>bolded</b></p>'
);
}
function testItFindsTopAncestor() {
$image = $this->root->query('img')->offsetGet(0);
$paragraph = $this->root->query('p')->offsetGet(0);
expect(DOMUtil::findTopAncestor($image))->equals($paragraph);
}
}