17 use ProtectedHookAccessorTrait;
23 $this->skinContext = $skinContext;
29 private function getTemplateDataFooter(): array {
31 'info' => $this->formatFooterInfoData(
32 $this->getFooterInfoData()
34 'places' => $this->getSiteFooterLinks(),
36 $skin = $this->skinContext->getContextSource()->getSkin();
37 foreach ( $data as $key => $existingItems ) {
39 $this->getHookRunner()->onSkinAddFooterLinks( $skin, $key, $newItems );
40 foreach ( $newItems as $index => $linkHTML ) {
41 $data[ $key ][ $index ] = [
42 'id' =>
'footer-' . $key .
'-' . $index,
54 $footerData = $this->getTemplateDataFooter();
60 $this->skinContext->getMessageLocalizer()
64 $footerData[
'places'],
65 $this->skinContext->getMessageLocalizer()
73 $footerMenuData[
'data-info'] = $footerInfoMenuData->getTemplateData();
74 $footerMenuData[
'data-places'] = $footerSiteMenuData->getTemplateData();
75 $footerMenuData[
'data-icons'] = $this->getFooterIcons();
76 $footerMenuData = $this->formatFooterDataForCurrentSpec( $footerMenuData );
79 'data-info' => $footerMenuData[
'data-info'],
80 'data-places' => $footerMenuData[
'data-places'],
81 'data-icons' => $footerMenuData[
'data-icons']
95 private function getFooterInfoData(): array {
97 $skinContext = $this->skinContext;
102 $titleExists = $title && $title->exists();
104 $maxCredits = $config->get( MainConfigNames::MaxCredits );
105 $showCreditsIfMax = $config->get( MainConfigNames::ShowCreditsIfMax );
106 $useCredits = $titleExists
108 && $out->isRevisionCurrent()
109 && $maxCredits !== 0;
113 $article = Article::newFromWikiPage( $skinContext->
getWikiPage(), $ctx );
114 $action = Action::factory(
'credits', $article, $ctx );
117 '@phan-var CreditsAction $action';
119 'lastmod' => !$useCredits ? $this->lastModified() : null,
120 'numberofwatchingusers' => null,
121 'credits' => $useCredits && $action ?
122 $action->getCredits( $maxCredits, $showCreditsIfMax ) : null,
123 'renderedwith' => $this->renderedWith(),
126 'copyright' => $titleExists &&
127 $out->showsCopyright() ? $this->getCopyright() : null,
134 private function getCopyright() {
135 $copyright =
new SkinComponentCopyright( $this->skinContext );
136 return $copyright->getTemplateData()[
'html' ];
148 private function formatFooterInfoData( array $data ): array {
150 foreach ( $data as $key => $item ) {
152 $formattedData[ $key ] = [
153 'id' =>
'footer-info-' . $key,
158 return $formattedData;
167 private function getSiteFooterLinks(): array {
170 'privacy' => [
'privacy',
'privacypage' ],
171 'about' => [
'aboutsite',
'aboutpage' ],
172 'disclaimers' => [
'disclaimers',
'disclaimerpage' ]
174 $localizer = $this->skinContext->getMessageLocalizer();
176 foreach ( $siteLinks as $key => $siteLink ) {
179 if ( !$localizer->msg( $siteLink[0] )->inContentLanguage()->isDisabled() ) {
182 $title = Title::newFromText( $localizer->msg( $siteLink[1] )->inContentLanguage()->text() );
183 if ( $title !==
null ) {
184 $siteLinksData[$key] = [
185 'id' =>
"footer-places-$key",
186 'text' => $localizer->msg( $siteLink[0] )->text(),
187 'href' => $title->fixSpecialName()->getLinkURL()
192 return $siteLinksData;
207 if ( is_string( $icon ) ) {
210 $url = $icon[
'url'] ??
null;
211 unset( $icon[
'url'] );
214 if ( isset( $icon[
'sources'] ) ) {
215 foreach ( $icon[
'sources'] as
$source ) {
216 $sources .= Html::element(
'source',
$source );
218 unset( $icon[
'sources'] );
221 if ( isset( $icon[
'src'] ) && $withImage ===
'withImage' ) {
223 $icon[
'loading'] =
'lazy';
225 $html = Html::element(
'img', $icon );
227 $html = Html::openElement(
'picture' ) . $sources . $html . Html::closeElement(
'picture' );
230 $html = htmlspecialchars( $icon[
'alt'] ??
'' );
233 $html = Html::rawElement(
239 'cdx-button',
'cdx-button--fake-button',
240 'cdx-button--size-large',
'cdx-button--fake-button--enabled'
242 'target' => $config->get( MainConfigNames::ExternalLinkTarget ),
261 $config->
get( MainConfigNames::FooterIcons ) as $footerIconsKey => &$footerIconsBlock
263 if ( count( $footerIconsBlock ) > 0 ) {
264 $footericons[$footerIconsKey] = [];
265 foreach ( $footerIconsBlock as &$footerIcon ) {
266 if ( isset( $footerIcon[
'src'] ) ) {
267 if ( !isset( $footerIcon[
'width'] ) ) {
268 $footerIcon[
'width'] = 88;
270 if ( !isset( $footerIcon[
'height'] ) ) {
271 $footerIcon[
'height'] = 31;
280 if ( is_string( $footerIcon ) || isset( $footerIcon[
'src'] ) ) {
281 $footericons[$footerIconsKey][] = $footerIcon;
287 if ( !count( $footericons[$footerIconsKey] ) ) {
288 unset( $footericons[$footerIconsKey] );
302 private function getFooterIcons(): array {
304 $skinContext = $this->skinContext;
307 $footerIcons = self::getFooterIconsData(
311 if ( count( $footerIcons ) > 0 ) {
313 foreach ( $footerIcons as $blockName => $blockIcons ) {
315 foreach ( $blockIcons as $icon ) {
316 $html .= self::makeFooterIconHTML(
323 $block = htmlspecialchars( $blockName );
326 'id' =>
'footer-' . $block .
'ico',
328 'class' => [
'noprint' ],
335 if ( count( $icons ) > 0 ) {
336 $dataIcons =
new SkinComponentMenu(
339 $this->skinContext->getMessageLocalizer(),
346 return $dataIcons ? $dataIcons->getTemplateData() : [];
360 private function formatFooterDataForCurrentSpec( array $data ): array {
362 foreach ( $data as $key => $item ) {
363 unset( $item[
'html-tooltip'] );
364 unset( $item[
'html-items'] );
365 unset( $item[
'html-after-portal'] );
366 unset( $item[
'html-before-portal'] );
367 unset( $item[
'label'] );
368 unset( $item[
'class'] );
369 foreach ( $item[
'array-items'] ?? [] as $index => $arrayItem ) {
370 unset( $item[
'array-items'][$index][
'html-item'] );
372 $formattedData[$key] = $item;
373 $formattedData[$key][
'className'] = $key ===
'data-icons' ?
'noprint' :
null;
375 return $formattedData;
384 private function lastModified() {
385 $skinContext = $this->skinContext;
387 $timestamp = $out->getRevisionTimestamp();
392 if ( $timestamp ===
null ) {
393 $revId = $out->getRevisionId();
394 if ( $revId !==
null ) {
395 $timestamp = MediaWikiServices::getInstance()->getRevisionLookup()->getTimestampFromId( $revId );
399 $lastModified =
new SkinComponentLastModified(
404 return $lastModified->getTemplateData()[
'text'];
413 private function renderedWith() {
414 $skinContext = $this->skinContext;
416 $useParsoid = $out->getOutputFlag( ParserOutputFlags::USE_PARSOID );
418 $renderedWith =
new SkinComponentRenderedWith(
423 return $renderedWith->getTemplateData()[
'text'];