Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
105 / 105 |
|
100.00% |
6 / 6 |
CRAP | |
100.00% |
1 / 1 |
MediaInfoEntityTermsView | |
100.00% |
105 / 105 |
|
100.00% |
6 / 6 |
18 | |
100.00% |
1 / 1 |
__construct | n/a |
0 / 0 |
n/a |
0 / 0 |
1 | |||||
getHtml | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
1 | |||
getCaptionsHeader | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
getLanguagesOrderedByFallbackChain | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
3 | |||
getCaptionsContent | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
6 | |||
getSingleCaptionLayout | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
3 | |||
getCaptionElementForLanguage | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 |
1 | <?php |
2 | |
3 | namespace Wikibase\MediaInfo\View; |
4 | |
5 | use MediaWiki\Html\Html; |
6 | use MediaWiki\Output\OutputPage; |
7 | use OOUI\Element; |
8 | use OOUI\HorizontalLayout; |
9 | use OOUI\LabelWidget; |
10 | use OOUI\PanelLayout; |
11 | use OOUI\Tag; |
12 | use Wikibase\DataModel\Term\TermList; |
13 | use Wikibase\Lib\LanguageNameLookup; |
14 | use Wikibase\Lib\TermLanguageFallbackChain; |
15 | use Wikibase\MediaInfo\DataModel\MediaInfo; |
16 | use Wikibase\View\LanguageDirectionalityLookup; |
17 | use Wikibase\View\LocalizedTextProvider; |
18 | |
19 | /** |
20 | * Generates HTML to display the terms of a MediaInfo entity |
21 | * |
22 | * @license GPL-2.0-or-later |
23 | */ |
24 | class MediaInfoEntityTermsView { |
25 | |
26 | /** |
27 | * @var LanguageNameLookup |
28 | */ |
29 | private $languageNameLookup; |
30 | |
31 | /** |
32 | * @var LanguageDirectionalityLookup |
33 | */ |
34 | private $languageDirectionalityLookup; |
35 | |
36 | /** |
37 | * @var LocalizedTextProvider |
38 | */ |
39 | private $textProvider; |
40 | |
41 | /** |
42 | * @var TermLanguageFallbackChain |
43 | */ |
44 | private $termFallbackChain; |
45 | |
46 | public const CAPTIONS_CUSTOM_TAG = 'mediaInfoViewCaptions'; |
47 | public const CAPTION_EMPTY_CLASS = 'wbmi-entityview-emptyCaption'; |
48 | public const HIDEABLE_CAPTION_CLASS = 'wbmi-entityview-hideable'; |
49 | private const CAPTIONS_CONTAINER = 'wbmi-entityview-captionsPanel'; |
50 | |
51 | /** |
52 | * @param LanguageNameLookup $languageNameLookup |
53 | * @param LanguageDirectionalityLookup $languageDirectionalityLookup |
54 | * @param LocalizedTextProvider $textProvider |
55 | * @param TermLanguageFallbackChain $termFallbackChain |
56 | * @codeCoverageIgnore |
57 | */ |
58 | public function __construct( |
59 | LanguageNameLookup $languageNameLookup, |
60 | LanguageDirectionalityLookup $languageDirectionalityLookup, |
61 | LocalizedTextProvider $textProvider, |
62 | TermLanguageFallbackChain $termFallbackChain |
63 | ) { |
64 | OutputPage::setupOOUI(); |
65 | |
66 | $this->languageNameLookup = $languageNameLookup; |
67 | $this->languageDirectionalityLookup = $languageDirectionalityLookup; |
68 | $this->textProvider = $textProvider; |
69 | $this->termFallbackChain = $termFallbackChain; |
70 | } |
71 | |
72 | /** |
73 | * @param MediaInfo $entity |
74 | * |
75 | * @return string HTML |
76 | */ |
77 | public function getHtml( |
78 | MediaInfo $entity |
79 | ) { |
80 | $layout = new PanelLayout( [ |
81 | 'classes' => [ self::CAPTIONS_CONTAINER ], |
82 | 'scrollable' => false, |
83 | 'padded' => false, |
84 | 'expanded' => false, |
85 | 'framed' => true, |
86 | ] ); |
87 | $layout->appendContent( $this->getCaptionsHeader() ); |
88 | $layout->appendContent( |
89 | $this->getCaptionsContent( |
90 | $entity->getLabels(), |
91 | $this->getLanguagesOrderedByFallbackChain( $entity ) |
92 | ) |
93 | ); |
94 | $html = $layout->toString(); |
95 | |
96 | // Wrap the whole thing in a custom tag so we can manipulate its position on the page |
97 | // later on |
98 | return Html::rawElement( |
99 | self::CAPTIONS_CUSTOM_TAG, |
100 | [], |
101 | $html |
102 | ); |
103 | } |
104 | |
105 | private function getCaptionsHeader() { |
106 | $header = new Tag( 'h3' ); |
107 | $header->addClasses( [ 'wbmi-entityview-captions-header' ] ); |
108 | $header->appendContent( |
109 | $this->textProvider->get( |
110 | 'wikibasemediainfo-entitytermsforlanguagelistview-caption' |
111 | ) |
112 | ); |
113 | return $header; |
114 | } |
115 | |
116 | /** |
117 | * Return the language codes for labels, in the following order: |
118 | * |
119 | * - the first language in the fallback chain (i.e. the interface language), whether or not |
120 | * a label exists in that language |
121 | * - the rest of the languages in the fallback chain for which a label exists, in order |
122 | * - all other languages for which a label exists (in any order) |
123 | * |
124 | * @param MediaInfo $entity |
125 | * @return array |
126 | */ |
127 | private function getLanguagesOrderedByFallbackChain( MediaInfo $entity ) { |
128 | $labelLanguages = array_keys( $entity->getLabels()->toTextArray() ); |
129 | $fbChainLanguages = $this->termFallbackChain->getFetchLanguageCodes(); |
130 | $orderedLangCodes = |
131 | array_values( |
132 | array_flip( |
133 | array_merge( |
134 | array_flip( |
135 | array_intersect( |
136 | $this->termFallbackChain->getFetchLanguageCodes(), |
137 | $labelLanguages |
138 | ) |
139 | ), |
140 | array_flip( $labelLanguages ) |
141 | ) |
142 | ) |
143 | ); |
144 | if ( |
145 | count( $fbChainLanguages ) > 0 && |
146 | !in_array( $fbChainLanguages[0], $orderedLangCodes ) |
147 | ) { |
148 | array_unshift( $orderedLangCodes, $fbChainLanguages[0] ); |
149 | } |
150 | return $orderedLangCodes; |
151 | } |
152 | |
153 | /** |
154 | * The following captions are always shown |
155 | * |
156 | * - the first caption |
157 | * - the first non-empty caption in the fallback chain IF AND ONLY IF the first caption has no |
158 | * value |
159 | * |
160 | * @param TermList $captions |
161 | * @param string[] $languageCodes |
162 | * @return Tag[] |
163 | */ |
164 | private function getCaptionsContent( |
165 | TermList $captions, |
166 | array $languageCodes |
167 | ) { |
168 | $captionLayouts = []; |
169 | |
170 | $firstCaptionHasNoValue = false; |
171 | foreach ( $languageCodes as $index => $languageCode ) { |
172 | if ( $index == 0 ) { |
173 | $showCaption = true; |
174 | $firstCaptionHasNoValue = !$captions->hasTermForLanguage( $languageCode ); |
175 | } elseif ( |
176 | $index == 1 && |
177 | $firstCaptionHasNoValue && |
178 | in_array( $languageCode, $this->termFallbackChain->getFetchLanguageCodes() ) |
179 | ) { |
180 | $showCaption = true; |
181 | } else { |
182 | $showCaption = false; |
183 | } |
184 | $captionLayouts[] = $this->getSingleCaptionLayout( |
185 | $captions, |
186 | $languageCode, |
187 | $showCaption |
188 | ); |
189 | } |
190 | |
191 | return $captionLayouts; |
192 | } |
193 | |
194 | /** |
195 | * @param TermList $labels |
196 | * @param string $languageCode |
197 | * @param bool $showCaption Hide the label (via styling) if false |
198 | * |
199 | * @return HorizontalLayout |
200 | */ |
201 | public function getSingleCaptionLayout( |
202 | TermList $labels, |
203 | $languageCode, |
204 | $showCaption |
205 | ) { |
206 | $languageName = $this->languageNameLookup->getName( $languageCode ); |
207 | |
208 | // This label should be shown in the UI direction rather than the |
209 | // language's direction since it's not editable. |
210 | $languageElement = new LabelWidget( [ |
211 | 'label' => $languageName, |
212 | 'classes' => [ 'wbmi-language-label' ] |
213 | ] ); |
214 | |
215 | $captionElement = $this->getCaptionElementForLanguage( |
216 | $labels, |
217 | $languageCode |
218 | ); |
219 | |
220 | $classes = [ 'wbmi-entityview-caption' ]; |
221 | if ( !$showCaption ) { |
222 | $classes[] = self::HIDEABLE_CAPTION_CLASS; |
223 | } |
224 | $layout = new HorizontalLayout( [ |
225 | 'items' => [ |
226 | $languageElement, |
227 | $captionElement, |
228 | ], |
229 | 'classes' => $classes, |
230 | ] ); |
231 | if ( !$showCaption ) { |
232 | $layout->setAttributes( [ |
233 | 'style' => 'display:none;', |
234 | ] ); |
235 | } |
236 | return $layout; |
237 | } |
238 | |
239 | private function getCaptionElementForLanguage( TermList $termList, $languageCode ) { |
240 | $classes = [ 'wbmi-caption-value' ]; |
241 | try { |
242 | $captionText = $termList->getByLanguage( $languageCode )->getText(); |
243 | } catch ( \OutOfBoundsException $e ) { |
244 | $captionText = htmlspecialchars( |
245 | $this->textProvider->get( 'wikibasemediainfo-filepage-caption-empty' ) |
246 | ); |
247 | $classes[] = self::CAPTION_EMPTY_CLASS; |
248 | } |
249 | |
250 | $captionElement = new Element( [ |
251 | 'content' => $captionText, |
252 | 'classes' => $classes, |
253 | ] ); |
254 | $captionElement->setAttributes( [ |
255 | 'lang' => $languageCode, |
256 | 'dir' => |
257 | $this->languageDirectionalityLookup->getDirectionality( $languageCode ) ?: 'auto', |
258 | ] ); |
259 | return $captionElement; |
260 | } |
261 | |
262 | } |