Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 14 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
QuoteHandler | |
0.00% |
0 / 14 |
|
0.00% |
0 / 3 |
72 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
handle | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
precedingQuoteEltRequiresEscape | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
20 |
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\SerializerState; |
9 | use Wikimedia\Parsoid\Utils\DiffDOMUtils; |
10 | use Wikimedia\Parsoid\Utils\DOMUtils; |
11 | |
12 | class QuoteHandler extends DOMHandler { |
13 | |
14 | /** @var string Quote sequence to match as opener/closer */ |
15 | public $quotes; |
16 | |
17 | /** |
18 | * @param string $quotes Quote sequence to match as opener/closer |
19 | */ |
20 | public function __construct( string $quotes ) { |
21 | parent::__construct( false ); |
22 | $this->quotes = $quotes; |
23 | } |
24 | |
25 | /** @inheritDoc */ |
26 | public function handle( |
27 | Element $node, SerializerState $state, bool $wrapperUnmodified = false |
28 | ): ?Node { |
29 | if ( $this->precedingQuoteEltRequiresEscape( $node ) ) { |
30 | $state->emitChunk( '<nowiki/>', $node ); |
31 | } |
32 | $state->emitChunk( $this->quotes, $node ); |
33 | |
34 | if ( $node->hasChildNodes() ) { |
35 | $state->serializeChildren( $node ); |
36 | } else { |
37 | // Empty nodes like <i></i> or <b></b> need |
38 | // a <nowiki/> in place of the empty content so that |
39 | // they parse back identically. |
40 | $state->emitChunk( '<nowiki/>', $node ); |
41 | } |
42 | |
43 | $state->emitChunk( $this->quotes, $node ); |
44 | return $node->nextSibling; |
45 | } |
46 | |
47 | private function precedingQuoteEltRequiresEscape( |
48 | Element $node |
49 | ): bool { |
50 | // * <i> and <b> siblings don't need a <nowiki/> separation |
51 | // as long as quote chars in text nodes are always |
52 | // properly escaped -- which they are right now. |
53 | // |
54 | // * Adjacent quote siblings need a <nowiki/> separation |
55 | // between them if either of them will individually |
56 | // generate a sequence of quotes 4 or longer. That can |
57 | // only happen when either prev or node is of the form: |
58 | // <i><b>...</b></i> |
59 | // |
60 | // For new/edited DOMs, this can never happen because |
61 | // wts.minimizeQuoteTags.js does quote tag minimization. |
62 | // |
63 | // For DOMs from existing wikitext, this can only happen |
64 | // because of auto-inserted end/start tags. (Ex: ''a''' b ''c''') |
65 | $prev = DiffDOMUtils::previousNonDeletedSibling( $node ); |
66 | return $prev && DOMUtils::isQuoteElt( $prev ) |
67 | && ( DOMUtils::isQuoteElt( DiffDOMUtils::lastNonDeletedChild( $prev ) ) |
68 | || DOMUtils::isQuoteElt( DiffDOMUtils::firstNonDeletedChild( $node ) ) ); |
69 | } |
70 | |
71 | } |