Skip to content

Commit

Permalink
IBX-5048: Fixed handling nested lists with line feeds (#237)
Browse files Browse the repository at this point in the history
* IBX-5048: Richtext editor not handling sublists when parent contains line breaks

* Fixed Ibexa namespace

* fixup! Fixed Ibexa namespace

* PHPstan

* fixup! PHPstan

* fixup! fixup! Fixed Ibexa namespace

* Update composer.json

Co-authored-by: Dawid Parafiński <[email protected]>

* fixup! PHPstan

* fixup! IBX-5048: Richtext editor not handling sublists when parent contains line breaks

* fixup! IBX-5048: Richtext editor not handling sublists when parent contains line breaks

---------

Co-authored-by: Vidar Langseid <[email protected]>
Co-authored-by: Dawid Parafiński <[email protected]>
  • Loading branch information
3 people authored Aug 17, 2023
1 parent 6bff30d commit 454e5cc
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 1 deletion.
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@
"autoload": {
"psr-4": {
"EzSystems\\EzPlatformRichTextBundle\\": "src/bundle",
"Ibexa\\FieldTypeRichText\\RichText\\": "src/lib/RichText",
"EzSystems\\EzPlatformRichText\\": "src/lib"
}
},
"autoload-dev": {
"psr-4": {
"EzSystems\\Tests\\EzPlatformRichText\\": "tests/lib",
"EzSystems\\Tests\\EzPlatformRichTextBundle\\": "tests/bundle",
"EzSystems\\IntegrationTests\\EzPlatformRichText\\": "tests/integration"
"EzSystems\\IntegrationTests\\EzPlatformRichText\\": "tests/integration",
"Ibexa\\Tests\\FieldTypeRichText\\": "tests/lib/Richtext"
}
},
"scripts": {
Expand Down
5 changes: 5 additions & 0 deletions src/bundle/Resources/config/fieldtype_services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ services:
tags:
- {name: ezrichtext.converter.input.xhtml5, priority: 10}

# Note: should run after xsl transformation
Ibexa\FieldTypeRichText\RichText\Converter\LiteralLayoutNestedList:
tags:
- {name: ezrichtext.converter.input.xhtml5, priority: 100}

ezrichtext.converter.edit.xhtml5:
class: EzSystems\EzPlatformRichTextBundle\eZ\RichText\Converter\Html5Edit
arguments:
Expand Down
70 changes: 70 additions & 0 deletions src/lib/RichText/Converter/LiteralLayoutNestedList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\FieldTypeRichText\RichText\Converter;

use DOMDocument;
use DOMElement;
use DOMNode;
use DOMXPath;
use EzSystems\EzPlatformRichText\eZ\RichText\Converter;

/**
* @internal
*
* Processes lists nested in <literallayout> tags.
*/
final class LiteralLayoutNestedList implements Converter
{
private const FALLBACK_NAMESPACE = 'http://docbook.org/ns/docbook';
private const ORDERED_LIST_TAG = 'orderedlist';
private const ITEMIZED_LIST_TAG = 'itemizedlist';

/**
* For all <itemizedList> and <orderedList> nested in the <literallayout>, move the list after the <literallayout>,
* so that it is not inside it.
*/
public function convert(DOMDocument $document): DOMDocument
{
$xpath = new DOMXPath($document);
$xpathExpression = '//ns:literallayout [descendant::ns:orderedlist|descendant::ns:itemizedlist]';
$xpath->registerNamespace(
'ns',
null !== $document->documentElement && !empty($document->documentElement->namespaceURI)
? $document->documentElement->namespaceURI
: self::FALLBACK_NAMESPACE
);
$elements = $xpath->query($xpathExpression) ?: [];

// elements are list of <literallayout> elements
/** @var DOMElement $element */
foreach ($elements as $element) {
/** @var DOMNode $childNode */
foreach ($element->childNodes as $childNode) {
if ($this->isNestedListNode($childNode)) {
$targetNode = $childNode->parentNode->parentNode;
if ($targetNode !== null) {
$targetNode->appendChild($childNode);
}
}
}
}

return $document;
}

/**
* @phpstan-assert-if-true !null $childNode->parentNode
*/
private function isNestedListNode(DOMNode $childNode): bool
{
return $childNode instanceof DOMElement
&& ($childNode->tagName === self::ORDERED_LIST_TAG || $childNode->tagName === self::ITEMIZED_LIST_TAG)
&& $childNode->parentNode !== null;
}
}
94 changes: 94 additions & 0 deletions tests/lib/Richtext/Converter/LiteralLayoutNestedListTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

/**
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Tests\FieldTypeRichText\RichText\Converter;

use Ibexa\FieldTypeRichText\RichText\Converter\LiteralLayoutNestedList;
use PHPUnit\Framework\TestCase;
use DOMDocument;

/**
* @covers \Ibexa\FieldTypeRichText\RichText\Converter\LiteralLayoutNestedList
*/
final class LiteralLayoutNestedListTest extends TestCase
{
/**
* @return array<int, array<int, string>>
*/
public function providerConvert(): array
{
return [
[
'<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0">
<para>This is a p</para>
<para> </para>
<itemizedlist>
<listitem>
<para>item 1</para>
</listitem>
<listitem>
<para>
<literallayout class="normal">item 2
this is a line 2
this is line 3<itemizedlist><listitem><para>item 3</para></listitem></itemizedlist></literallayout>
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para> </para>
</listitem>
</itemizedlist>
</section>',
'<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0">
<para>This is a p</para>
<para> </para>
<itemizedlist>
<listitem>
<para>item 1</para>
</listitem>
<listitem>
<para>
<literallayout class="normal">item 2
this is a line 2
this is line 3</literallayout>
<itemizedlist><listitem><para>item 3</para></listitem></itemizedlist></para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para> </para>
</listitem>
</itemizedlist>
</section> ',
],
];
}

/**
* Test conversion of <li> tags which containing <br/> and <ol>/<ul> tags.
*
* @dataProvider providerConvert
*/
public function testConvert(string $input, string $output): void
{
$inputDocument = new DOMDocument();
$inputDocument->loadXML($input);

$converter = new LiteralLayoutNestedList();

$outputDocument = $converter->convert($inputDocument);

$expectedOutputDocument = new DOMDocument();
$expectedOutputDocument->loadXML($output);

self::assertEquals($expectedOutputDocument, $outputDocument);
}
}
2 changes: 2 additions & 0 deletions tests/lib/eZ/RichText/Converter/Xslt/Xhtml5ToDocbookTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace EzSystems\Tests\EzPlatformRichText\eZ\RichText\Converter\Xslt;

use EzSystems\EzPlatformRichText\eZ\RichText\Converter\Aggregate;
use Ibexa\FieldTypeRichText\RichText\Converter\LiteralLayoutNestedList;
use EzSystems\EzPlatformRichText\eZ\RichText\Converter\ProgramListing;
use EzSystems\EzPlatformRichText\eZ\RichText\Converter\Xslt;

Expand Down Expand Up @@ -110,6 +111,7 @@ protected function getConverter()
$this->getConversionTransformationStylesheet(),
$this->getCustomConversionTransformationStylesheets()
),
new LiteralLayoutNestedList(),
]
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0">
<para>This is a p</para>
<para> </para>
<orderedlist>
<listitem>
<para>item 1</para>
</listitem>
<listitem>
<para>
<literallayout class="normal">item 2
this is a line 2
this is line 3</literallayout>
<orderedlist>
<listitem>
<para>item 3</para>
</listitem>
</orderedlist>
</para>
</listitem>
</orderedlist>
<orderedlist>
<listitem>
<para> </para>
</listitem>
</orderedlist>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://docbook.org/ns/docbook" xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0-variant ezpublish-1.0">
<para>This is a p</para>
<para> </para>
<itemizedlist>
<listitem>
<para>item 1</para>
</listitem>
<listitem>
<para>
<literallayout class="normal">item 2
this is a line 2
this is line 3</literallayout>
<itemizedlist>
<listitem>
<para>item 3</para>
</listitem>
</itemizedlist>
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para> </para>
</listitem>
</itemizedlist>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://ez.no/namespaces/ezpublish5/xhtml5/edit">
<p>This is a p</p>
<p> </p>
<ol>
<li>item 1</li>
<li>item 2<br/>this is a line 2<br/>this is line 3<ol><li>item 3</li></ol></li>
</ol>
<ol>
<li> </li>
</ol>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://ez.no/namespaces/ezpublish5/xhtml5/edit">
<p>This is a p</p>
<p> </p>
<ul>
<li>item 1</li>
<li>item 2<br/>this is a line 2<br/>this is line 3<ul><li>item 3</li></ul></li>
</ul>
<ul>
<li> </li>
</ul>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://ez.no/namespaces/ezpublish5/xhtml5">
<p>This is a p</p>
<p> </p>
<ol>
<li>item 1</li>
<li>item 2<br/>this is a line 2<br/>this is line 3<ol><li>item 3</li></ol></li>
</ol>
<ol>
<li> </li>
</ol>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<section xmlns="http://ez.no/namespaces/ezpublish5/xhtml5">
<p>This is a p</p>
<p> </p>
<ul>
<li>item 1</li>
<li>item 2<br/>this is a line 2<br/>this is line 3<ul><li>item 3</li></ul></li>
</ul>
<ul>
<li> </li>
</ul>
</section>

0 comments on commit 454e5cc

Please sign in to comment.