Update Posts transformer to extract images by splitting the DOM tree
This commit is contained in:
@ -2,6 +2,7 @@
|
|||||||
namespace MailPoet\Newsletter\Editor;
|
namespace MailPoet\Newsletter\Editor;
|
||||||
|
|
||||||
use pQuery;
|
use pQuery;
|
||||||
|
use MailPoet\Util\DOM as DOMUtil;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -17,29 +18,22 @@ class StructureTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hoists images to root level, preserves order
|
* Hoists images to root level, preserves order by splitting neighboring
|
||||||
* and inserts tags before top ancestor
|
* elements and inserts tags as children of top ancestor
|
||||||
*/
|
*/
|
||||||
private function hoistImagesToRoot($root) {
|
protected function hoistImagesToRoot($root) {
|
||||||
foreach($root->query('img') as $item) {
|
foreach($root->query('img') as $item) {
|
||||||
$top_ancestor = $this->findTopAncestor($item);
|
$top_ancestor = DOMUtil::findTopAncestor($item);
|
||||||
$offset = $top_ancestor->index();
|
$offset = $top_ancestor->index();
|
||||||
|
|
||||||
if($item->hasParent('a')) {
|
if($item->hasParent('a')) {
|
||||||
$item = $item->parent;
|
$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,
|
* Transforms HTML tags into their respective JSON objects,
|
||||||
* turns other root children into text blocks
|
* turns other root children into text blocks
|
||||||
|
40
lib/Util/DOM.php
Normal file
40
lib/Util/DOM.php
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
30
tests/unit/Newsletter/Editor/StructureTransformerTest.php
Normal file
30
tests/unit/Newsletter/Editor/StructureTransformerTest.php
Normal 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>');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
tests/unit/Util/DOMTest.php
Normal file
29
tests/unit/Util/DOMTest.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user