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\DOMDataUtils; |
| 12 | use Wikimedia\Parsoid\Utils\DOMUtils; |
| 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 = DOMUtils::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 | } |