Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 28 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
MediaStructure | |
0.00% |
0 / 28 |
|
0.00% |
0 / 6 |
306 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
isRedLink | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getResource | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAlt | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getMediaUrl | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
parse | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
90 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\Core; |
5 | |
6 | use Wikimedia\Parsoid\DOM\Element; |
7 | use Wikimedia\Parsoid\DOM\Node; |
8 | use Wikimedia\Parsoid\Utils\DiffDOMUtils; |
9 | use Wikimedia\Parsoid\Utils\DOMCompat; |
10 | use Wikimedia\Parsoid\Utils\WTUtils; |
11 | use Wikimedia\Parsoid\Wikitext\Consts; |
12 | |
13 | /** |
14 | * All media should have a fixed structure: |
15 | * |
16 | * ``` |
17 | * <conatinerElt> |
18 | * <linkElt><mediaElt /></linkElt> |
19 | * <captionElt>...</captionElt> |
20 | * </containerElt> |
21 | * ``` |
22 | * |
23 | * Pull out this fixed structure, being as generous as possible with |
24 | * possibly-broken HTML. |
25 | */ |
26 | class MediaStructure { |
27 | |
28 | /** |
29 | * Node names: figure, span |
30 | * |
31 | * @var ?Element |
32 | */ |
33 | public $containerElt; |
34 | |
35 | /** |
36 | * Node names: a, span |
37 | * |
38 | * @var ?Element |
39 | */ |
40 | public $linkElt; |
41 | |
42 | /** |
43 | * Node names: img, audio, video, span |
44 | * |
45 | * @var ?Element |
46 | */ |
47 | public $mediaElt; |
48 | |
49 | /** |
50 | * Node names: figcaption |
51 | * |
52 | * @var ?Element |
53 | */ |
54 | public $captionElt; |
55 | |
56 | /** |
57 | * @param Element $mediaElt |
58 | * @param ?Element $linkElt |
59 | * @param ?Element $containerElt |
60 | */ |
61 | public function __construct( |
62 | Element $mediaElt, ?Element $linkElt = null, |
63 | ?Element $containerElt = null |
64 | ) { |
65 | $this->mediaElt = $mediaElt; |
66 | $this->linkElt = $linkElt; |
67 | $this->containerElt = $containerElt; |
68 | if ( $containerElt && DOMCompat::nodeName( $containerElt ) === 'figure' ) { |
69 | // FIXME: Support last child, which is not the linkElt, as the caption? |
70 | $this->captionElt = DOMCompat::querySelector( $containerElt, 'figcaption' ); |
71 | } |
72 | } |
73 | |
74 | /** |
75 | * We were not able to fetch info for the title, so the media was |
76 | * considered missing and rendered as a span. |
77 | * |
78 | * @return bool |
79 | */ |
80 | public function isRedLink(): bool { |
81 | return ( DOMCompat::nodeName( $this->mediaElt ) === 'span' ); |
82 | } |
83 | |
84 | /** |
85 | * @return ?string the resource name if it exists, otherwise null |
86 | */ |
87 | public function getResource(): ?string { |
88 | return DOMCompat::getAttribute( $this->mediaElt, 'resource' ); |
89 | } |
90 | |
91 | /** |
92 | * @return ?string The alt text if it exists, otherwise null |
93 | */ |
94 | public function getAlt(): ?string { |
95 | return DOMCompat::getAttribute( $this->mediaElt, 'alt' ); |
96 | } |
97 | |
98 | /** |
99 | * @return ?string The media href if it exists, otherwise null. |
100 | */ |
101 | public function getMediaUrl(): ?string { |
102 | return $this->linkElt ? |
103 | DOMCompat::getAttribute( $this->linkElt, 'href' ) : |
104 | null; |
105 | } |
106 | |
107 | /** |
108 | * @param Node $node |
109 | * @return ?MediaStructure |
110 | */ |
111 | public static function parse( Node $node ): ?MediaStructure { |
112 | if ( !WTUtils::isGeneratedFigure( $node ) ) { |
113 | return null; |
114 | } |
115 | '@phan-var Element $node'; // @var Element $node |
116 | $linkElt = $node; |
117 | do { |
118 | // Try being lenient, maybe there was a content model violation when |
119 | // parsing and an active formatting element was reopened in the wrapper |
120 | $linkElt = DiffDOMUtils::firstNonSepChild( $linkElt ); |
121 | } while ( |
122 | $linkElt instanceof Element && DOMCompat::nodeName( $linkElt ) !== 'a' && |
123 | isset( Consts::$HTML['FormattingTags'][DOMCompat::nodeName( $linkElt )] ) |
124 | ); |
125 | if ( |
126 | !( $linkElt instanceof Element && |
127 | in_array( DOMCompat::nodeName( $linkElt ), [ 'a', 'span' ], true ) ) |
128 | ) { |
129 | if ( $linkElt instanceof Element ) { |
130 | // Try being lenient, maybe this is the media element and we don't |
131 | // have a link elt. See the test, "Image: from basic HTML (1)" |
132 | $mediaElt = $linkElt; |
133 | $linkElt = null; |
134 | } else { |
135 | return null; |
136 | } |
137 | } else { |
138 | $mediaElt = DiffDOMUtils::firstNonSepChild( $linkElt ); |
139 | } |
140 | if ( |
141 | !( $mediaElt instanceof Element && |
142 | in_array( DOMCompat::nodeName( $mediaElt ), [ 'audio', 'img', 'span', 'video' ], true ) ) |
143 | ) { |
144 | return null; |
145 | } |
146 | return new MediaStructure( $mediaElt, $linkElt, $node ); |
147 | } |
148 | |
149 | } |