Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 43 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
TDHandler | |
0.00% |
0 / 43 |
|
0.00% |
0 / 4 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
handle | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
306 | |||
before | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
after | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\Html2Wt\DOMHandlers; |
5 | |
6 | use Wikimedia\Parsoid\DOM\Element; |
7 | use Wikimedia\Parsoid\DOM\Node; |
8 | use Wikimedia\Parsoid\Html2Wt\DiffUtils; |
9 | use Wikimedia\Parsoid\Html2Wt\SerializerState; |
10 | use Wikimedia\Parsoid\Utils\DiffDOMUtils; |
11 | use Wikimedia\Parsoid\Utils\DOMCompat; |
12 | use Wikimedia\Parsoid\Utils\DOMDataUtils; |
13 | |
14 | class TDHandler extends DOMHandler { |
15 | |
16 | public function __construct() { |
17 | parent::__construct( false ); |
18 | } |
19 | |
20 | /** @inheritDoc */ |
21 | public function handle( |
22 | Element $node, SerializerState $state, bool $wrapperUnmodified = false |
23 | ): ?Node { |
24 | $dp = DOMDataUtils::getDataParsoid( $node ); |
25 | $usableDP = $this->stxInfoValidForTableCell( $state, $node ); |
26 | $attrSepSrc = $usableDP ? ( $dp->attrSepSrc ?? null ) : null; |
27 | $startTagSrc = $usableDP ? ( $dp->startTagSrc ?? null ) : ''; |
28 | if ( !$startTagSrc ) { |
29 | $startTagSrc = ( $usableDP && ( $dp->stx ?? null ) === 'row' ) ? '||' : '|'; |
30 | } |
31 | |
32 | // T149209: Special case to deal with scenarios |
33 | // where the previous sibling put us in a SOL state |
34 | // (or will put in a SOL state when the separator is emitted) |
35 | $min = $state->sep->constraints['min'] ?? 0; |
36 | $max = $state->sep->constraints['max'] ?? 1; |
37 | if ( $min > 0 || ( $max > 0 && str_contains( $state->sep->src ?? '', "\n" ) ) ) { |
38 | $startTagSrc = preg_replace( '/\|\|/', '|', $startTagSrc, 1 ); |
39 | $startTagSrc = preg_replace( '/{{!}}{{!}}/', '{{!}}', $startTagSrc, 1 ); |
40 | } |
41 | |
42 | // If the HTML for the first td is not enclosed in a tr-tag, |
43 | // we start a new line. If not, tr will have taken care of it. |
44 | $tdTag = $this->serializeTableTag( |
45 | $startTagSrc, $attrSepSrc, |
46 | $state, $node, $wrapperUnmodified |
47 | ); |
48 | $inWideTD = (bool)preg_match( '/\|\||^{{!}}{{!}}/', $tdTag ); |
49 | $leadingSpace = $this->getLeadingSpace( $state, $node, '' ); |
50 | $state->emitChunk( $tdTag . $leadingSpace, $node ); |
51 | $tdHandler = static function ( $state, $text, $opts ) use ( $node, $inWideTD ) { |
52 | return $state->serializer->wteHandlers->tdHandler( $node, $inWideTD, $state, $text, $opts ); |
53 | }; |
54 | |
55 | $nextTd = DiffDOMUtils::nextNonSepSibling( $node ); |
56 | $nextUsesRowSyntax = $nextTd instanceof Element |
57 | && ( DOMDataUtils::getDataParsoid( $nextTd )->stx ?? null ) === 'row'; |
58 | |
59 | // For empty cells, emit a single whitespace to make wikitext |
60 | // more readable as well as to eliminate potential misparses. |
61 | if ( $nextUsesRowSyntax && !DiffDOMUtils::firstNonDeletedChild( $node ) ) { |
62 | $state->serializer->emitWikitext( ' ', $node ); |
63 | return $node->nextSibling; |
64 | } |
65 | |
66 | $state->serializeChildren( $node, $tdHandler ); |
67 | |
68 | if ( !preg_match( '/\s$/D', $state->currLine->text ) ) { |
69 | $trailingSpace = ''; |
70 | if ( $nextUsesRowSyntax ) { |
71 | $trailingSpace = $this->getTrailingSpace( $state, $node, '' ); |
72 | } |
73 | // Recover any trimmed whitespace only on unmodified nodes |
74 | if ( $trailingSpace === '' ) { |
75 | $lastChild = DiffDOMUtils::lastNonSepChild( $node ); |
76 | if ( $lastChild && !DiffUtils::hasDiffMarkers( $lastChild ) ) { |
77 | $trailingSpace = $state->recoverTrimmedWhitespace( $node, false ) ?? ''; |
78 | } |
79 | } |
80 | $state->appendSep( $trailingSpace ); |
81 | } |
82 | |
83 | return $node->nextSibling; |
84 | } |
85 | |
86 | /** @inheritDoc */ |
87 | public function before( Element $node, Node $otherNode, SerializerState $state ): array { |
88 | $forceSingleLine = DOMCompat::nodeName( $otherNode ) === 'td' |
89 | && ( DOMDataUtils::getDataParsoid( $node )->stx ?? null ) === 'row'; |
90 | return [ 'min' => $forceSingleLine ? 0 : 1, 'max' => $this->maxNLsInTable( $node, $otherNode ) ]; |
91 | } |
92 | |
93 | /** @inheritDoc */ |
94 | public function after( Element $node, Node $otherNode, SerializerState $state ): array { |
95 | return [ 'min' => 0, 'max' => $this->maxNLsInTable( $node, $otherNode ) ]; |
96 | } |
97 | |
98 | } |