From 454e5cc3a1244ca272b5304fdf0fcf52ec8b5cfa Mon Sep 17 00:00:00 2001 From: Vidar Date: Thu, 17 Aug 2023 11:39:02 +0200 Subject: [PATCH] IBX-5048: Fixed handling nested lists with line feeds (#237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 * 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 Co-authored-by: Dawid Parafiński --- composer.json | 4 +- .../Resources/config/fieldtype_services.yaml | 5 + .../Converter/LiteralLayoutNestedList.php | 70 ++++++++++++++ .../Converter/LiteralLayoutNestedListTest.php | 94 +++++++++++++++++++ .../Converter/Xslt/Xhtml5ToDocbookTest.php | 2 + .../docbook/036-orderedListWithLinefeeds.xml | 27 ++++++ .../docbook/037-itemizedListWithLinefeeds.xml | 27 ++++++ .../edit/036-orderedListWithLinefeeds.xml | 12 +++ .../edit/037-itemizedListWithLinefeeds.xml | 12 +++ .../output/036-orderedListWithLinefeeds.xml | 12 +++ .../output/037-itemizedListWithLinefeeds.xml | 12 +++ 11 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 src/lib/RichText/Converter/LiteralLayoutNestedList.php create mode 100644 tests/lib/Richtext/Converter/LiteralLayoutNestedListTest.php create mode 100644 tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/036-orderedListWithLinefeeds.xml create mode 100644 tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/037-itemizedListWithLinefeeds.xml create mode 100644 tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/036-orderedListWithLinefeeds.xml create mode 100644 tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/037-itemizedListWithLinefeeds.xml create mode 100644 tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/036-orderedListWithLinefeeds.xml create mode 100644 tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/037-itemizedListWithLinefeeds.xml diff --git a/composer.json b/composer.json index fe8ac2a7..80aceac3 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,7 @@ "autoload": { "psr-4": { "EzSystems\\EzPlatformRichTextBundle\\": "src/bundle", + "Ibexa\\FieldTypeRichText\\RichText\\": "src/lib/RichText", "EzSystems\\EzPlatformRichText\\": "src/lib" } }, @@ -52,7 +53,8 @@ "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": { diff --git a/src/bundle/Resources/config/fieldtype_services.yaml b/src/bundle/Resources/config/fieldtype_services.yaml index 54f020a7..02f17d26 100644 --- a/src/bundle/Resources/config/fieldtype_services.yaml +++ b/src/bundle/Resources/config/fieldtype_services.yaml @@ -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: diff --git a/src/lib/RichText/Converter/LiteralLayoutNestedList.php b/src/lib/RichText/Converter/LiteralLayoutNestedList.php new file mode 100644 index 00000000..56d84e11 --- /dev/null +++ b/src/lib/RichText/Converter/LiteralLayoutNestedList.php @@ -0,0 +1,70 @@ + 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 and nested in the , move the list after the , + * 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 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; + } +} diff --git a/tests/lib/Richtext/Converter/LiteralLayoutNestedListTest.php b/tests/lib/Richtext/Converter/LiteralLayoutNestedListTest.php new file mode 100644 index 00000000..0b1f9116 --- /dev/null +++ b/tests/lib/Richtext/Converter/LiteralLayoutNestedListTest.php @@ -0,0 +1,94 @@ +> + */ + public function providerConvert(): array + { + return [ + [ + ' +
+ This is a p + + + + item 1 + + + + item 2 +this is a line 2 +this is line 3item 3 + + + + + + + + +
', + ' +
+ This is a p + + + + item 1 + + + + item 2 +this is a line 2 +this is line 3 + item 3 + + + + + + + +
', + ], + ]; + } + + /** + * Test conversion of
  • tags which containing
    and
      /
        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); + } +} diff --git a/tests/lib/eZ/RichText/Converter/Xslt/Xhtml5ToDocbookTest.php b/tests/lib/eZ/RichText/Converter/Xslt/Xhtml5ToDocbookTest.php index 9f227f64..c9a24926 100644 --- a/tests/lib/eZ/RichText/Converter/Xslt/Xhtml5ToDocbookTest.php +++ b/tests/lib/eZ/RichText/Converter/Xslt/Xhtml5ToDocbookTest.php @@ -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; @@ -110,6 +111,7 @@ protected function getConverter() $this->getConversionTransformationStylesheet(), $this->getCustomConversionTransformationStylesheets() ), + new LiteralLayoutNestedList(), ] ); } diff --git a/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/036-orderedListWithLinefeeds.xml b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/036-orderedListWithLinefeeds.xml new file mode 100644 index 00000000..cd608d69 --- /dev/null +++ b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/036-orderedListWithLinefeeds.xml @@ -0,0 +1,27 @@ + +
        + This is a p +   + + + item 1 + + + + item 2 +this is a line 2 +this is line 3 + + + item 3 + + + + + + + +   + + +
        diff --git a/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/037-itemizedListWithLinefeeds.xml b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/037-itemizedListWithLinefeeds.xml new file mode 100644 index 00000000..4c324978 --- /dev/null +++ b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/docbook/037-itemizedListWithLinefeeds.xml @@ -0,0 +1,27 @@ + +
        + This is a p +   + + + item 1 + + + + item 2 +this is a line 2 +this is line 3 + + + item 3 + + + + + + + +   + + +
        diff --git a/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/036-orderedListWithLinefeeds.xml b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/036-orderedListWithLinefeeds.xml new file mode 100644 index 00000000..1c0f10a3 --- /dev/null +++ b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/036-orderedListWithLinefeeds.xml @@ -0,0 +1,12 @@ + +
        +

        This is a p

        +

         

        +
          +
        1. item 1
        2. +
        3. item 2
          this is a line 2
          this is line 3
          1. item 3
        4. +
        +
          +
        1.  
        2. +
        +
        diff --git a/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/037-itemizedListWithLinefeeds.xml b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/037-itemizedListWithLinefeeds.xml new file mode 100644 index 00000000..ba5bf7d8 --- /dev/null +++ b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/edit/037-itemizedListWithLinefeeds.xml @@ -0,0 +1,12 @@ + +
        +

        This is a p

        +

         

        +
          +
        • item 1
        • +
        • item 2
          this is a line 2
          this is line 3
          • item 3
        • +
        +
          +
        •  
        • +
        +
        diff --git a/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/036-orderedListWithLinefeeds.xml b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/036-orderedListWithLinefeeds.xml new file mode 100644 index 00000000..ef841ffe --- /dev/null +++ b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/036-orderedListWithLinefeeds.xml @@ -0,0 +1,12 @@ + +
        +

        This is a p

        +

         

        +
          +
        1. item 1
        2. +
        3. item 2
          this is a line 2
          this is line 3
          1. item 3
        4. +
        +
          +
        1.  
        2. +
        +
        diff --git a/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/037-itemizedListWithLinefeeds.xml b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/037-itemizedListWithLinefeeds.xml new file mode 100644 index 00000000..d5c1c088 --- /dev/null +++ b/tests/lib/eZ/RichText/Converter/Xslt/_fixtures/xhtml5/output/037-itemizedListWithLinefeeds.xml @@ -0,0 +1,12 @@ + +
        +

        This is a p

        +

         

        +
          +
        • item 1
        • +
        • item 2
          this is a line 2
          this is line 3
          • item 3
        • +
        +
          +
        •  
        • +
        +