Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F5989483
SkinComponentFooter.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
SkinComponentFooter.php
View Options
<?php
namespace
MediaWiki\Skin
;
use
Action
;
use
Article
;
use
CreditsAction
;
use
MediaWiki\Config\Config
;
use
MediaWiki\HookContainer\ProtectedHookAccessorTrait
;
use
MediaWiki\Html\Html
;
use
MediaWiki\MainConfigNames
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Title\Title
;
class
SkinComponentFooter
implements
SkinComponent
{
use
ProtectedHookAccessorTrait
;
/** @var SkinComponentRegistryContext */
private
$skinContext
;
/**
* @param SkinComponentRegistryContext $skinContext
*/
public
function
__construct
(
SkinComponentRegistryContext
$skinContext
)
{
$this
->
skinContext
=
$skinContext
;
}
/**
* Run SkinAddFooterLinks hook on menu data to insert additional menu items specifically in footer.
*
* @return array
*/
private
function
getTemplateDataFooter
():
array
{
$data
=
[
'info'
=>
$this
->
formatFooterInfoData
(
$this
->
getFooterInfoData
()
),
'places'
=>
$this
->
getSiteFooterLinks
(),
];
$skin
=
$this
->
skinContext
->
getContextSource
()->
getSkin
();
foreach
(
$data
as
$key
=>
$existingItems
)
{
$newItems
=
[];
$this
->
getHookRunner
()->
onSkinAddFooterLinks
(
$skin
,
$key
,
$newItems
);
foreach
(
$newItems
as
$index
=>
$linkHTML
)
{
$data
[
$key
][
$index
]
=
[
'id'
=>
'footer-'
.
$key
.
'-'
.
$index
,
'html'
=>
$linkHTML
,
];
}
}
return
$data
;
}
/**
* @inheritDoc
*/
public
function
getTemplateData
():
array
{
$footerData
=
$this
->
getTemplateDataFooter
();
// Create the menu components from the footer data.
$footerInfoMenuData
=
new
SkinComponentMenu
(
'footer-info'
,
$footerData
[
'info'
],
$this
->
skinContext
->
getMessageLocalizer
()
);
$footerSiteMenuData
=
new
SkinComponentMenu
(
'footer-places'
,
$footerData
[
'places'
],
$this
->
skinContext
->
getMessageLocalizer
()
);
// To conform the footer menu data to the current SkinMustache specification,
// run the derived data through a cleanup function to unset unexpected data properties
// until the spec is updated to reflect the new properties introduced by the menu component.
// See https://www.mediawiki.org/wiki/Manual:SkinMustache.php#DataFooter
$footerMenuData
=
[];
$footerMenuData
[
'data-info'
]
=
$footerInfoMenuData
->
getTemplateData
();
$footerMenuData
[
'data-places'
]
=
$footerSiteMenuData
->
getTemplateData
();
$footerMenuData
[
'data-icons'
]
=
$this
->
getFooterIcons
();
$footerMenuData
=
$this
->
formatFooterDataForCurrentSpec
(
$footerMenuData
);
return
[
'data-info'
=>
$footerMenuData
[
'data-info'
],
'data-places'
=>
$footerMenuData
[
'data-places'
],
'data-icons'
=>
$footerMenuData
[
'data-icons'
]
];
}
/**
* Get the footer data containing standard footer links.
*
* All values are resolved and can be added to by the
* SkinAddFooterLinks hook.
*
* @since 1.40
* @internal
* @return array
*/
private
function
getFooterInfoData
():
array
{
$action
=
null
;
$skinContext
=
$this
->
skinContext
;
$out
=
$skinContext
->
getOutput
();
$ctx
=
$skinContext
->
getContextSource
();
// This needs to be the relevant Title rather than just the raw Title for e.g. special pages that render content
$title
=
$skinContext
->
getRelevantTitle
();
$titleExists
=
$title
&&
$title
->
exists
();
$config
=
$skinContext
->
getConfig
();
$maxCredits
=
$config
->
get
(
MainConfigNames
::
MaxCredits
);
$showCreditsIfMax
=
$config
->
get
(
MainConfigNames
::
ShowCreditsIfMax
);
$useCredits
=
$titleExists
&&
$out
->
isArticle
()
&&
$out
->
isRevisionCurrent
()
&&
$maxCredits
!==
0
;
/** @var CreditsAction $action */
if
(
$useCredits
)
{
$article
=
Article
::
newFromWikiPage
(
$skinContext
->
getWikiPage
(),
$ctx
);
$action
=
Action
::
factory
(
'credits'
,
$article
,
$ctx
);
}
'@phan-var CreditsAction $action'
;
return
[
'lastmod'
=>
!
$useCredits
?
$this
->
lastModified
()
:
null
,
'numberofwatchingusers'
=>
null
,
'credits'
=>
$useCredits
&&
$action
?
$action
->
getCredits
(
$maxCredits
,
$showCreditsIfMax
)
:
null
,
'copyright'
=>
$titleExists
&&
$out
->
showsCopyright
()
?
$this
->
getCopyright
()
:
null
,
];
}
/**
* @return string
*/
private
function
getCopyright
()
{
$copyright
=
new
SkinComponentCopyright
(
$this
->
skinContext
);
return
$copyright
->
getTemplateData
()[
'html'
];
}
/**
* Format the footer data containing standard footer links for passing
* into SkinComponentMenu.
*
* @since 1.40
* @internal
* @param array $data raw footer data
* @return array
*/
private
function
formatFooterInfoData
(
array
$data
):
array
{
$formattedData
=
[];
foreach
(
$data
as
$key
=>
$item
)
{
if
(
$item
)
{
$formattedData
[
$key
]
=
[
'id'
=>
'footer-info-'
.
$key
,
'html'
=>
$item
];
}
}
return
$formattedData
;
}
/**
* Gets the link to the wiki's privacy policy, about page, and disclaimer page
*
* @internal
* @return array data array for 'privacy', 'about', 'disclaimer'
*/
private
function
getSiteFooterLinks
():
array
{
$siteLinksData
=
[];
$siteLinks
=
[
'privacy'
=>
[
'privacy'
,
'privacypage'
],
'about'
=>
[
'aboutsite'
,
'aboutpage'
],
'disclaimers'
=>
[
'disclaimers'
,
'disclaimerpage'
]
];
$localizer
=
$this
->
skinContext
->
getMessageLocalizer
();
foreach
(
$siteLinks
as
$key
=>
$siteLink
)
{
// Check if the link description has been disabled in the default language.
// If disabled, it is disabled for all languages.
if
(
!
$localizer
->
msg
(
$siteLink
[
0
]
)->
inContentLanguage
()->
isDisabled
()
)
{
// Display the link for the user, described in their language (which may or may not be the same as the
// default language), but make the link target be the one site-wide page.
$title
=
Title
::
newFromText
(
$localizer
->
msg
(
$siteLink
[
1
]
)->
inContentLanguage
()->
text
()
);
if
(
$title
!==
null
)
{
$siteLinksData
[
$key
]
=
[
'id'
=>
"footer-places-$key"
,
'text'
=>
$localizer
->
msg
(
$siteLink
[
0
]
)->
text
(),
'href'
=>
$title
->
fixSpecialName
()->
getLinkURL
()
];
}
}
}
return
$siteLinksData
;
}
/**
* Renders a $wgFooterIcons icon according to the method's arguments
*
* @param Config $config
* @param array|string $icon The icon to build the html for, see $wgFooterIcons
* for the format of this array.
* @param string $withImage Whether to use the icon's image or output
* a text-only footer icon.
* @return string HTML
* @internal for use in Skin only
*/
public
static
function
makeFooterIconHTML
(
Config
$config
,
$icon
,
string
$withImage
=
'withImage'
):
string
{
if
(
is_string
(
$icon
)
)
{
$html
=
$icon
;
}
else
{
// Assuming array
$url
=
$icon
[
'url'
]
??
null
;
unset
(
$icon
[
'url'
]
);
if
(
isset
(
$icon
[
'src'
]
)
&&
$withImage
===
'withImage'
)
{
// Lazy-load footer icons, since they're not part of the printed view.
$icon
[
'loading'
]
=
'lazy'
;
// do this the lazy way, just pass icon data as an attribute array
$html
=
Html
::
element
(
'img'
,
$icon
);
}
else
{
$html
=
htmlspecialchars
(
$icon
[
'alt'
]
??
''
);
}
if
(
$url
)
{
$html
=
Html
::
rawElement
(
'a'
,
[
'href'
=>
$url
,
// Using a fake Codex link button, as this is the long-expected UX; our apologies.
'class'
=>
[
'cdx-button'
,
'cdx-button--fake-button'
,
'cdx-button--size-large'
,
'cdx-button--fake-button--enabled'
],
'target'
=>
$config
->
get
(
MainConfigNames
::
ExternalLinkTarget
),
],
$html
);
}
}
return
$html
;
}
/**
* Get data representation of icons
*
* @internal for use in Skin only
* @param Config $config
* @return array
*/
public
static
function
getFooterIconsData
(
Config
$config
)
{
$footericons
=
[];
foreach
(
$config
->
get
(
MainConfigNames
::
FooterIcons
)
as
$footerIconsKey
=>
&
$footerIconsBlock
)
{
if
(
count
(
$footerIconsBlock
)
>
0
)
{
$footericons
[
$footerIconsKey
]
=
[];
foreach
(
$footerIconsBlock
as
&
$footerIcon
)
{
if
(
isset
(
$footerIcon
[
'src'
]
)
)
{
if
(
!
isset
(
$footerIcon
[
'width'
]
)
)
{
$footerIcon
[
'width'
]
=
88
;
}
if
(
!
isset
(
$footerIcon
[
'height'
]
)
)
{
$footerIcon
[
'height'
]
=
31
;
}
}
// Only output icons which have an image.
// For historic reasons this mimics the `icononly` option
// for BaseTemplate::getFooterIcons.
// In some cases the icon may be an empty array.
// Filter these out. (See T269776)
if
(
is_string
(
$footerIcon
)
||
isset
(
$footerIcon
[
'src'
]
)
)
{
$footericons
[
$footerIconsKey
][]
=
$footerIcon
;
}
}
// If no valid icons with images were added, unset the parent array
// Should also prevent empty arrays from when no copyright is set.
if
(
!
count
(
$footericons
[
$footerIconsKey
]
)
)
{
unset
(
$footericons
[
$footerIconsKey
]
);
}
}
}
return
$footericons
;
}
/**
* Gets the link to the wiki's privacy policy, about page, and disclaimer page
*
* @internal
* @return array data array for 'privacy', 'about', 'disclaimer'
* @suppress SecurityCheck-DoubleEscaped
*/
private
function
getFooterIcons
():
array
{
$dataIcons
=
[];
$skinContext
=
$this
->
skinContext
;
// If footer icons are enabled append to the end of the rows
$footerIcons
=
$skinContext
->
getFooterIcons
();
if
(
count
(
$footerIcons
)
>
0
)
{
$icons
=
[];
foreach
(
$footerIcons
as
$blockName
=>
$blockIcons
)
{
$html
=
''
;
foreach
(
$blockIcons
as
$icon
)
{
$html
.=
$skinContext
->
makeFooterIcon
(
$icon
);
}
// For historic reasons this mimics the `icononly` option
// for BaseTemplate::getFooterIcons. Empty rows should not be output.
if
(
$html
)
{
$block
=
htmlspecialchars
(
$blockName
);
$icons
[
$block
]
=
[
'name'
=>
$block
,
'id'
=>
'footer-'
.
$block
.
'ico'
,
'html'
=>
$html
,
'class'
=>
[
'noprint'
],
];
}
}
// Empty rows should not be output.
// This is how Vector has behaved historically but we can revisit later if necessary.
if
(
count
(
$icons
)
>
0
)
{
$dataIcons
=
new
SkinComponentMenu
(
'footer-icons'
,
$icons
,
$this
->
skinContext
->
getMessageLocalizer
(),
''
,
[]
);
}
}
return
$dataIcons
?
$dataIcons
->
getTemplateData
()
:
[];
}
/**
* Get finalized footer menu data and reformat to fit current specification.
*
* See https://www.mediawiki.org/wiki/Manual:SkinMustache.php#DataFooter
* This method should be removed once the specification is updated and
* new data properties provided by the menu component are ok to output.
*
* @internal
* @param array $data
* @return array
*/
private
function
formatFooterDataForCurrentSpec
(
array
$data
):
array
{
$formattedData
=
[];
foreach
(
$data
as
$key
=>
$item
)
{
unset
(
$item
[
'html-tooltip'
]
);
unset
(
$item
[
'html-items'
]
);
unset
(
$item
[
'html-after-portal'
]
);
unset
(
$item
[
'html-before-portal'
]
);
unset
(
$item
[
'label'
]
);
unset
(
$item
[
'class'
]
);
foreach
(
$item
[
'array-items'
]
??
[]
as
$index
=>
$arrayItem
)
{
unset
(
$item
[
'array-items'
][
$index
][
'html-item'
]
);
}
$formattedData
[
$key
]
=
$item
;
$formattedData
[
$key
][
'className'
]
=
$key
===
'data-icons'
?
'noprint'
:
null
;
}
return
$formattedData
;
}
/**
* Get the timestamp of the latest revision, formatted in user language
*
* @internal for use in Skin.php only
* @return string
*/
private
function
lastModified
()
{
$skinContext
=
$this
->
skinContext
;
$out
=
$skinContext
->
getOutput
();
$timestamp
=
$out
->
getRevisionTimestamp
();
// No cached timestamp, load it from the database
// TODO: This code shouldn't be necessary, revision ID should always be available
// Move this logic to OutputPage::getRevisionTimestamp if needed.
if
(
$timestamp
===
null
)
{
$revId
=
$out
->
getRevisionId
();
if
(
$revId
!==
null
)
{
$timestamp
=
MediaWikiServices
::
getInstance
()->
getRevisionLookup
()->
getTimestampFromId
(
$revId
);
}
}
$lastModified
=
new
SkinComponentLastModified
(
$skinContext
,
$timestamp
);
return
$lastModified
->
getTemplateData
()[
'text'
];
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sun, Oct 4, 01:08 (3 w, 4 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
3a/a3/7da976b234ae7be5dc2831ee4b05
Default Alt Text
SkinComponentFooter.php (11 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment