Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 21 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
ContentHeadingItem | |
0.00% |
0 / 21 |
|
0.00% |
0 / 9 |
210 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getLinkableTitle | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
isUneditableSection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setUneditableSection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getHeadingLevel | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setHeadingLevel | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isPlaceholderHeading | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setPlaceholderHeading | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
jsonSerialize | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\DiscussionTools\ThreadItem; |
4 | |
5 | use MediaWiki\Extension\DiscussionTools\ImmutableRange; |
6 | use Wikimedia\Assert\Assert; |
7 | use Wikimedia\Parsoid\DOM\Element; |
8 | |
9 | class ContentHeadingItem extends ContentThreadItem implements HeadingItem { |
10 | use HeadingItemTrait { |
11 | jsonSerialize as traitJsonSerialize; |
12 | } |
13 | |
14 | private bool $placeholderHeading; |
15 | private int $headingLevel; |
16 | private bool $uneditableSection = false; |
17 | |
18 | // Placeholder headings must have a level higher than real headings (1-6) |
19 | private const PLACEHOLDER_HEADING_LEVEL = 99; |
20 | |
21 | /** |
22 | * @param ImmutableRange $range |
23 | * @param bool|string $transcludedFrom |
24 | * @param ?int $headingLevel Heading level (1-6). Use null for a placeholder heading. |
25 | */ |
26 | public function __construct( |
27 | ImmutableRange $range, $transcludedFrom, ?int $headingLevel |
28 | ) { |
29 | parent::__construct( 'heading', 0, $range, $transcludedFrom ); |
30 | $this->placeholderHeading = $headingLevel === null; |
31 | $this->headingLevel = $this->placeholderHeading ? static::PLACEHOLDER_HEADING_LEVEL : $headingLevel; |
32 | } |
33 | |
34 | /** |
35 | * Get a title based on the hash ID, such that it can be linked to |
36 | * |
37 | * @return string Title |
38 | */ |
39 | public function getLinkableTitle(): string { |
40 | $title = ''; |
41 | // If this comment is in 0th section, there's no section title for the edit summary |
42 | if ( !$this->isPlaceholderHeading() ) { |
43 | // <span class="mw-headline" …>, or <hN …> in Parsoid HTML |
44 | $headline = $this->getRange()->startContainer; |
45 | Assert::precondition( $headline instanceof Element, 'HeadingItem refers to an element node' ); |
46 | $id = $headline->getAttribute( 'id' ) ?: $headline->getAttribute( 'data-mw-anchor' ); |
47 | if ( $id ) { |
48 | // Replace underscores with spaces to undo Sanitizer::escapeIdInternal(). |
49 | // This assumes that $wgFragmentMode is [ 'html5', 'legacy' ] or [ 'html5' ], |
50 | // otherwise the escaped IDs are super garbled and can't be unescaped reliably. |
51 | $title = str_replace( '_', ' ', $id ); |
52 | } |
53 | // else: Not a real section, probably just HTML markup in wikitext |
54 | } |
55 | return $title; |
56 | } |
57 | |
58 | public function isUneditableSection(): bool { |
59 | return $this->uneditableSection; |
60 | } |
61 | |
62 | /** |
63 | * @param bool $uneditableSection The heading represents a section that can't be |
64 | * edited on its own. |
65 | */ |
66 | public function setUneditableSection( bool $uneditableSection ): void { |
67 | $this->uneditableSection = $uneditableSection; |
68 | } |
69 | |
70 | /** |
71 | * @return int Heading level (1-6) |
72 | */ |
73 | public function getHeadingLevel(): int { |
74 | return $this->headingLevel; |
75 | } |
76 | |
77 | /** |
78 | * @param int $headingLevel Heading level (1-6) |
79 | */ |
80 | public function setHeadingLevel( int $headingLevel ): void { |
81 | $this->headingLevel = $headingLevel; |
82 | } |
83 | |
84 | public function isPlaceholderHeading(): bool { |
85 | return $this->placeholderHeading; |
86 | } |
87 | |
88 | public function setPlaceholderHeading( bool $placeholderHeading ): void { |
89 | $this->placeholderHeading = $placeholderHeading; |
90 | } |
91 | |
92 | /** |
93 | * @inheritDoc |
94 | */ |
95 | public function jsonSerialize( bool $deep = false, ?callable $callback = null ): array { |
96 | $data = $this->traitJsonSerialize( $deep, $callback ); |
97 | |
98 | // When this is false (which is most of the time), omit the key for efficiency |
99 | if ( $this->isUneditableSection() ) { |
100 | $data[ 'uneditableSection' ] = true; |
101 | } |
102 | return $data; |
103 | } |
104 | } |