diff --git a/lib/Newsletter/Editor/StructureTransformer.php b/lib/Newsletter/Editor/StructureTransformer.php index 08d1222a1b..06dcdf6ebf 100644 --- a/lib/Newsletter/Editor/StructureTransformer.php +++ b/lib/Newsletter/Editor/StructureTransformer.php @@ -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 diff --git a/lib/Util/DOM.php b/lib/Util/DOM.php new file mode 100644 index 0000000000..380f734f3a --- /dev/null +++ b/lib/Util/DOM.php @@ -0,0 +1,40 @@ +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; + } + +} diff --git a/tests/unit/Newsletter/Editor/StructureTransformerTest.php b/tests/unit/Newsletter/Editor/StructureTransformerTest.php new file mode 100644 index 0000000000..ca6d736f54 --- /dev/null +++ b/tests/unit/Newsletter/Editor/StructureTransformerTest.php @@ -0,0 +1,30 @@ +transformer = new StructureTransformer(); + } + + function testItExtractsImagesAsImageBlocks() { + $html = '
italicprevious textnext textbolded
italicprevious text
'); + + 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('next textbolded
'); + } + +} diff --git a/tests/unit/Util/DOMTest.php b/tests/unit/Util/DOMTest.php new file mode 100644 index 0000000000..12b3698f22 --- /dev/null +++ b/tests/unit/Util/DOMTest.php @@ -0,0 +1,29 @@ +root = pQuery::parseStr('italicprevious textnext textbolded
italicprevious text
'. + 'next textbolded
' + ); + } + + function testItFindsTopAncestor() { + $image = $this->root->query('img')->offsetGet(0); + $paragraph = $this->root->query('p')->offsetGet(0); + + expect(DOMUtil::findTopAncestor($image))->equals($paragraph); + } +}