35 private const MENU_LABEL_KEYS = [
36 'cactions' =>
'vector-more-actions',
38 'personal' =>
'personaltools',
39 'lang' =>
'otherlanguages',
42 private const MENU_TYPE_DEFAULT = 0;
44 private const MENU_TYPE_TABS = 1;
46 private const MENU_TYPE_DROPDOWN = 2;
59 private const OPT_OUT_LINK_TRACKING_CODE =
'vctw1';
79 parent::__construct( $config );
82 $this->isLegacy = $isLegacy;
83 $this->templateRoot = $isLegacy ?
'skin-legacy' :
'skin';
99 if ( $this->templateParser ===
null ) {
100 throw new \LogicException(
101 'TemplateParser has to be set first via setTemplateParser method'
116 $out = $skin->getOutput();
117 $title = $out->getTitle();
135 $mainPageHref = Skin::makeMainPageUrl();
137 $newTalksHtml = $skin->getNewtalks() ?:
null;
140 $commonSkinData = $skin->getTemplateData() + [
141 'html-headelement' => $out->headElement( $skin ),
142 'page-langcode' =>
$title->getPageViewLanguage()->getHtmlCode(),
143 'page-isarticle' => (bool)$out->isArticle(),
147 'html-title' => $out->getPageTitle(),
148 'msg-tagline' => $skin->msg(
'tagline' )->text(),
150 'html-newtalk' => $newTalksHtml ?
'<div class="usermessage">' . $newTalksHtml .
'</div>' :
'',
152 'msg-vector-jumptonavigation' => $skin->msg(
'vector-jumptonavigation' )->text(),
153 'msg-vector-jumptosearch' => $skin->msg(
'vector-jumptosearch' )->text(),
155 'html-printfooter' => $skin->printSource(),
156 'html-categories' => $skin->getCategories(),
158 'html-navigation-heading' => $skin->msg(
'navigation-heading' ),
163 'msg-sitetitle' => $skin->msg(
'sitetitle' )->text(),
164 'msg-sitesubtitle' => $skin->msg(
'sitesubtitle' )->text(),
165 'main-page-href' => $mainPageHref,
169 'msg-vector-action-toggle-sidebar' => $skin->msg(
'vector-action-toggle-sidebar' )->text(),
174 if ( !$this->isLegacy && $skin->getUser()->isLoggedIn() ) {
175 $commonSkinData[
'data-sidebar'][
'data-emphasized-sidebar-action'] = [
179 'mw-prefsection-rendering-skin-skin-prefs'
180 )->getLinkURL(
'wprov=' . self::OPT_OUT_LINK_TRACKING_CODE ),
181 'text' => $skin->msg(
'vector-opt-out' )->text(),
182 'title' => $skin->msg(
'vector-opt-out-tooltip' )->text(),
186 return $commonSkinData;
193 $tp = $this->getTemplateParser();
194 echo $tp->processTemplate( $this->templateRoot, $this->getSkinData() );
202 $skin = $this->getSkin();
204 foreach ( $this->getFooterLinks() as $category => $links ) {
206 $rowId =
"footer-$category";
208 foreach ( $links as $link ) {
210 'id' =>
"$rowId-$link",
211 'html' => $this->
get( $link,
'' ),
218 'array-items' => $items
223 $footerIcons = $this->getFooterIcons(
'icononly' );
224 if ( count( $footerIcons ) > 0 ) {
226 foreach ( $footerIcons as $blockName => $blockIcons ) {
228 foreach ( $blockIcons as $icon ) {
229 $html .= $skin->makeFooterIcon( $icon );
232 'id' =>
'footer-' . htmlspecialchars( $blockName ) .
'ico',
238 'id' =>
'footer-icons',
239 'className' =>
'noprint',
240 'array-items' => $items,
245 Hooks::run(
'VectorBeforeFooter', [],
'1.35' );
246 $htmlHookVectorBeforeFooter = ob_get_contents();
250 'html-hook-vector-before-footer' => $htmlHookVectorBeforeFooter,
251 'array-footer-rows' => $footerRows,
263 $skin = $this->getSkin();
264 if ( $skin->getUser()->isLoggedIn() ) {
265 $userPrefSidebarState = $skin->getUser()->getOption(
266 Constants::PREF_KEY_SIDEBAR_VISIBLE
269 $defaultLoggedinSidebarState = $this->getConfig()->get(
270 Constants::CONFIG_KEY_DEFAULT_SIDEBAR_VISIBLE_FOR_AUTHORISED_USER
275 return ( $userPrefSidebarState !==
null )
276 ? (bool)$userPrefSidebarState
277 : $defaultLoggedinSidebarState;
279 return $this->getConfig()->get(
280 Constants::CONFIG_KEY_DEFAULT_SIDEBAR_VISIBLE_FOR_ANONYMOUS_USER
290 $skin = $this->getSkin();
291 $portals = $skin->buildSidebar();
296 foreach ( $portals as $name =>
$content ) {
302 $name = (string)$name;
308 $portal = $this->getMenuData(
309 'tb',
$content, self::MENU_TYPE_PORTAL
314 Hooks::run(
'VectorAfterToolbox', [],
'1.35' );
315 $props[] = $portal + [
316 'html-hook-vector-after-toolbox' => ob_get_clean(),
320 $portal = $this->getMenuData(
323 self::MENU_TYPE_PORTAL
328 if ( count(
$content ) || $portal[
'html-after-portal'] ) {
329 $languages = $portal;
339 "`content` field in portal $name must be array."
340 .
"Previously it could be a string but this is no longer supported.",
346 $portal = $this->getMenuData(
347 $name,
$content, self::MENU_TYPE_PORTAL
350 $portal[
'html-items'] .= $html;
357 $firstPortal = $props[0] ??
null;
358 if ( $firstPortal ) {
359 $firstPortal[
'class' ] .=
' portal-first';
363 'has-logo' => $this->isLegacy,
366 'class' =>
'mw-wiki-logo',
367 'href' => Skin::makeMainPageUrl(),
370 'array-portals-rest' => array_slice( $props, 1 ),
371 'data-portals-first' => $firstPortal,
372 'data-portals-languages' => $languages,
391 int $type = self::MENU_TYPE_DEFAULT,
393 bool $setLabelToSelected =
false
395 $skin = $this->getSkin();
397 self::MENU_TYPE_DROPDOWN =>
'vector-menu vector-menu-dropdown vectorMenu',
398 self::MENU_TYPE_TABS =>
'vector-menu vector-menu-tabs vectorTabs',
399 self::MENU_TYPE_PORTAL =>
'vector-menu vector-menu-portal portal',
400 self::MENU_TYPE_DEFAULT =>
'vector-menu',
406 self::MENU_TYPE_DROPDOWN =>
'menu vector-menu-content-list',
408 $isPortal = self::MENU_TYPE_PORTAL ===
$type;
412 $msgObj = $skin->msg( self::MENU_LABEL_KEYS[ $label ] ?? $label );
415 'label-id' =>
"p-{$label}-label",
417 'label' => $msgObj->exists() ? $msgObj->text() : $label,
418 'list-classes' => $listClasses[
$type] ??
'vector-menu-content-list',
420 'is-dropdown' => self::MENU_TYPE_DROPDOWN ===
$type,
424 foreach ( $urls as $key => $item ) {
427 $key !==
'watch' && $key !==
'unwatch' &&
428 isset( $options[
'vector-collapsible'] ) && $options[
'vector-collapsible'] ) {
429 if ( !isset( $item[
'class'] ) ) {
432 $item[
'class'] = rtrim(
'collapsible ' . $item[
'class'],
' ' );
434 $props[
'html-items'] .= $this->getSkin()->makeListItem( $key, $item, $options );
438 if ( $setLabelToSelected ) {
439 if ( isset( $item[
'class'] ) && stripos( $item[
'class'],
'selected' ) !==
false ) {
440 $props[
'label'] = $item[
'text'];
445 $props[
'html-after-portal'] = $isPortal ? $this->getAfterPortlet( $label ) :
'';
448 $class = ( count( $urls ) == 0 && !$props[
'html-after-portal'] )
449 ?
'vector-menu-empty emptyPortlet' :
'';
450 $props[
'class'] = trim(
"$class $extraClasses[$type]" );
459 $contentNavigation = $this->getSkin()->getMenuProps();
460 $personalTools = $this->getPersonalTools();
461 $skin = $this->getSkin();
468 if ( !$skin->getUser()->isLoggedIn() && User::groupHasPermission(
'*',
'edit' ) ) {
471 [
'id' =>
'pt-anonuserpage' ],
472 $skin->msg(
'notloggedin' )->text()
480 if ( array_key_exists(
'uls', $personalTools ) ) {
481 $uls = $skin->makeListItem(
'uls', $personalTools[
'uls' ] );
482 unset( $personalTools[
'uls' ] );
487 $ptools = $this->getMenuData(
'personal', $personalTools );
489 $ptools[
'html-items'] = $uls . $loggedIn . $ptools[
'html-items'];
492 'data-personal-menu' => $ptools,
493 'data-namespace-tabs' => $this->getMenuData(
495 $contentNavigation[
'namespaces' ] ?? [],
498 'data-variants' => $this->getMenuData(
500 $contentNavigation[
'variants' ] ?? [],
501 self::MENU_TYPE_DROPDOWN,
504 'data-page-actions' => $this->getMenuData(
506 $contentNavigation[
'views' ] ?? [],
507 self::MENU_TYPE_TABS, [
508 'vector-collapsible' =>
true,
511 'data-page-actions-more' => $this->getMenuData(
513 $contentNavigation[
'actions' ] ?? [],
514 self::MENU_TYPE_DROPDOWN
523 $config = $this->getConfig();
524 $skin = $this->getSkin();
526 'form-action' => $config->get(
'Script' ),
527 'html-button-search-fallback' => $this->makeSearchButton(
529 [
'id' =>
'mw-searchButton',
'class' =>
'searchButton mw-fallbackSearchButton' ]
531 'html-button-search' => $this->makeSearchButton(
533 [
'id' =>
'searchButton',
'class' =>
'searchButton' ]
535 'html-input' => $this->makeSearchInput( [
'id' =>
'searchInput' ] ),
536 'msg-search' => $skin->msg(
'search' ),
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
New base template for a skin's template extended from QuickTemplate this class features helper method...
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
static tooltip( $name, $options=null)
Returns raw bits of HTML, use titleAttrib()
static tooltipAndAccesskeyAttribs( $name, array $msgParams=[], $options=null)
Returns the attributes for the tooltip and access key.
getSkin()
Get the Skin object related to this object.
static getAvailableLogos( $conf)
Return an array of all available logos that a skin may use.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
QuickTemplate subclass for Vector.
getFooterData()
Get rows that make up the footer.
getTemplateParser()
The template parser might be undefined.
execute()
Renders the entire contents of the HTML page.
buildSidebar()
Render a series of portals.
string $templateRoot
File name of the root (master) template without folder path and extension.
TemplateParser $templateParser
isSidebarVisible()
Determines wheather the initial state of sidebar is visible on not.
getMenuData(string $label, array $urls=[], int $type=self::MENU_TYPE_DEFAULT, array $options=[], bool $setLabelToSelected=false)
__construct(Config $config, TemplateParser $templateParser, bool $isLegacy)
A namespace for Vector constants for internal Vector usage only.
static expandAttributes( $attribs)
Given an array of ('attributename' => 'value'), it generates the code to set the XML attributes : att...
Interface for configuration instances.