Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
PoemProcessor
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 2
156
0.00% covered (danger)
0.00%
0 / 1
 wtPostprocess
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 processNowikis
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\Poem\Parsoid;
5
6use Wikimedia\Parsoid\DOM\Element;
7use Wikimedia\Parsoid\DOM\Node;
8use Wikimedia\Parsoid\DOM\Text;
9use Wikimedia\Parsoid\Ext\DOMProcessor;
10use Wikimedia\Parsoid\Ext\DOMUtils;
11use Wikimedia\Parsoid\Ext\ParsoidExtensionAPI;
12
13class PoemProcessor extends DOMProcessor {
14
15    /**
16     * @inheritDoc
17     */
18    public function wtPostprocess(
19        ParsoidExtensionAPI $extApi, Node $node, array $options
20    ): void {
21        $c = $node->firstChild;
22        while ( $c ) {
23            if ( $c instanceof Element ) {
24                if ( DOMUtils::hasTypeOf( $c, 'mw:Extension/poem' ) ) {
25                    // Replace newlines found in <nowiki> fragment with <br/>s
26                    self::processNowikis( $c );
27                } else {
28                    $this->wtPostprocess( $extApi, $c, $options );
29                }
30            }
31            $c = $c->nextSibling;
32        }
33    }
34
35    private function processNowikis( Element $node ): void {
36        $doc = $node->ownerDocument;
37        $c = $node->firstChild;
38        while ( $c ) {
39            if ( !$c instanceof Element ) {
40                $c = $c->nextSibling;
41                continue;
42            }
43
44            if ( !DOMUtils::hasTypeOf( $c, 'mw:Nowiki' ) ) {
45                self::processNowikis( $c );
46                $c = $c->nextSibling;
47                continue;
48            }
49
50            // Replace the nowiki's text node with a combination
51            // of content and <br/>s. Take care to deal with
52            // entities that are still entity-wrapped (!!).
53            $cc = $c->firstChild;
54            while ( $cc ) {
55                $next = $cc->nextSibling;
56                if ( $cc instanceof Text ) {
57                    $pieces = preg_split( '/\n/', $cc->nodeValue ?? '' );
58                    $n = count( $pieces );
59                    $nl = '';
60                    for ( $i = 0;  $i < $n;  $i++ ) {
61                        $p = $pieces[$i];
62                        $c->insertBefore( $doc->createTextNode( $nl . $p ), $cc );
63                        if ( $i < $n - 1 ) {
64                            $c->insertBefore( $doc->createElement( 'br' ), $cc );
65                            $nl = "\n";
66                        }
67                    }
68                    $c->removeChild( $cc );
69                }
70                $cc = $next;
71            }
72            $c = $c->nextSibling;
73        }
74    }
75}