mediawiki-skins-Vector/includes/SkinVector.php

511 lines
17 KiB
PHP
Raw Normal View History

<?php
/**
* Vector - Modern version of MonoBook with fresh look and many usability
* improvements.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
* @ingroup Skins
*/
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
use MediaWiki\MediaWikiServices;
use Vector\Constants;
use Vector\VectorServices;
/**
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
* Skin subclass for Vector
* @ingroup Skins
* Skins extending SkinVector are not supported
* @package Vector
* @internal
*/
class SkinVector extends SkinMustache {
/** @var null|array for caching purposes */
private $languages;
/** @var int */
private const MENU_TYPE_DEFAULT = 0;
/** @var int */
private const MENU_TYPE_TABS = 1;
/** @var int */
private const MENU_TYPE_DROPDOWN = 2;
private const MENU_TYPE_PORTAL = 3;
Add opt-out link to Sidebar for Vector/Logged-in Users Without Abstractions This commit is singularly focused on adding a link to the sidebar for Vector, logged-in users. It does the bare minimum to fulfill the requirements of T243281. Additionally, it will help to answer the question "Do we need to use abstractions (other than maybe different templates) to separate Legacy Vector from Vector" by intentionally leaving out any abstractions in order to make it easier to compare with a follow-up patch (Ib2ef15180df73360cc1de25b893e49d415d23e1a) which does use abstractions. It is a good thing to question whether or not we need addtional abstractions in VectorTemplate and if they will help us as unnecessary abstractions can have the opposite effect and just lead to further frustrations down the road. Therefore, I urge you, the reviewer, to let me know your thoughts! If abstractions are viewed as not making our lives any easier, the follow-up patches may be completely discarded and that's totally okay with me. :) I think it's a good think to talk about now though. Important changes: * The VectorTemplate constructor was changed to allow injecting the config, templateParser, and isLegacy boolean (only the config was allowed before this commit). According to MediaWiki's Stable Interface Policy, "Constructor signatures are generally considered unstable unless explicitly declared stable for calling" [3]. Given that VecorTemplate's constructor is not marked as stable, it is justified to do this without warning according to the policy. * Due to the above, the 'setTemplate' method is no longer needed and was marked as deprecated. * VectorTemplateTest was made to adapt to the new VectorTemplate constructor. Additionally, it now extends from MediaWikiIntegrationTestCase which my intelliphense server can pick up. I *think* MediaWikiTestCase is just an alias to MediaWikiIntegrationTestCase [1] and MediaWikiTestCase file was renamed to MediaWikiIntegrationTestCase in [2], but I'm willing to change it back if there is pushback to this. Open questions: * What are VectorTemplate's responsibilities? To me, it acts right now as a controller (because it echos the full HTML string from the template), a model (because SkinTemplate::prepareQuickTemplate sets data on it which it later retrieves through `$this->get()`), a presenter (because it adds data tailored for a web-centric view), and a view (because it renders HTML strings instead of letting the view/template be solely responsible for that). Arguably, some business logic might be mixed in there as well (because it checks to see if a User is logged in/has necessary permissions to show x which my changes here add to). This might not be a problem if we keep VectorTemplate relatively small, but will it remain this way as we progress further in Desktop Improvements? * How do we write tests for VectorTemplate without exposing unnecessary public methods? For example, if I want to test the `getSkinData()` method to see what state will be sent to the template, how should I do this? One option might be to use `TestingAccessWrapper` to expose these private methods which is what `VectorTemplateTest::testbuildViewsProps()` does. Another option is to accept this method as public. Is there a better way? Keep in mind that even with access to this method, there might be many things to mock. [1] https://github.com/wikimedia/mediawiki/blob/0030cb525be6cabc1d63de80586b2017d4bbe354/tests/common/TestsAutoLoader.php#L64 [2] Ie717b0ecf4fcfd089d46248f14853c80b7ef4a76 [3] https://www.mediawiki.org/wiki/Stable_interface_policy Bug: T243281 Change-Id: I0571b041bcd7f19bec9f103fa7bccdd093f6394d
2020-03-17 20:21:33 +00:00
/**
* T243281: Code used to track clicks to opt-out link.
*
* The "vct" substring is used to describe the newest "Vector" (non-legacy)
* feature. The "w" describes the web platform. The "1" describes the version
* of the feature.
*
* @see https://wikitech.wikimedia.org/wiki/Provenance
* @var string
*/
private const OPT_OUT_LINK_TRACKING_CODE = 'vctw1';
/**
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
* Whether or not the legacy version of the skin is being used.
*
* @return bool
*/
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
private function isLegacy() : bool {
$isLatestSkinFeatureEnabled = MediaWikiServices::getInstance()
->getService( Constants::SERVICE_FEATURE_MANAGER )
->isFeatureEnabled( Constants::FEATURE_LATEST_SKIN );
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
return !$isLatestSkinFeatureEnabled;
}
/**
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
* Overrides template, styles and scripts module when skin operates
* in legacy mode.
*
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
* @inheritDoc
* @param array|null $options Note; this param is only optional for internal purpose.
* Do not instantiate Vector, use SkinFactory to create the object instead.
* If you absolutely must to, this paramater is required; you have to provide the
* skinname with the `name` key. That's do it with `new SkinVector( ['name' => 'vector'] )`.
* Failure to do that, will lead to fatal exception.
*/
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
public function __construct( $options = [] ) {
if ( $this->isLegacy() ) {
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
$options['scripts'] = [ 'skins.vector.legacy.js' ];
$options['styles'] = [ 'skins.vector.styles.legacy' ];
$options['template'] = 'skin-legacy';
} else {
// For historic reasons, the viewport is added when Vector is loaded on the mobile
// domain. This is only possible for 3rd parties or by useskin parameter as there is
// no preference for changing mobile skin.
$responsive = $this->getConfig()->get( 'VectorResponsive' );
if ( ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) ) {
$mobFrontContext = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' );
if ( $mobFrontContext->shouldDisplayMobileView() ) {
$responsive = true;
}
}
$options['responsive'] = $responsive;
}
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
$options['templateDirectory'] = __DIR__ . '/templates';
parent::__construct( $options );
}
/**
* Calls getLanguages with caching.
* @return array
*/
private function getLanguagesCached() : array {
if ( $this->languages !== null ) {
return $this->languages;
}
$this->languages = $this->getLanguages();
return $this->languages;
}
/**
* This should be upstreamed to the Skin class in core once the logic is finalized.
* Returns false if the page is a special page without any languages, or if an action
* other than view is being used.
* @return bool
*/
private function canHaveLanguages() : bool {
$action = Action::getActionName( $this->getContext() );
if ( $action !== 'view' ) {
return false;
}
$title = $this->getTitle();
// Defensive programming - if a special page has added languages explicitly, best to show it.
if ( $title && $title->isSpecialPage() && empty( $this->getLanguagesCached() ) ) {
return false;
}
return true;
}
/**
* @return bool
*/
private function isLanguagesInHeader() {
$featureManager = VectorServices::getFeatureManager();
// Disable button on pages without languages (based on Wikibase RepoItemLinkGenerator class)
return $this->canHaveLanguages() && $featureManager->isFeatureEnabled(
Constants::FEATURE_LANGUAGE_IN_HEADER
);
}
/**
* If in modern Vector and no languages possible, OR the languages in header button
* is enabled but language array is empty, then we shouldn't show the langauge list.
* @return bool
*/
private function shouldHideLanguages() {
return !$this->isLegacy() &&
!$this->canHaveLanguages() ||
// NOTE: T276950 - This should be revisited when an empty state for the language button is chosen.
( $this->isLanguagesInHeader() && empty( $this->getLanguagesCached() ) );
}
/**
* If in modern Vector and the config is set to consolidate user links, enable user link consolidation.
* @return bool
*/
private function shouldConsolidateUserLinks() {
$featureManager = VectorServices::getFeatureManager();
return !$this->isLegacy() &&
$featureManager->isFeatureEnabled(
Constants::FEATURE_CONSOLIDATE_USER_LINKS
);
}
/**
* Returns HTML for the create account button inside the anon user links
* @param string[] $returnto array of query strings used to build the login link
* @return string
*/
private function getCreateAccountHTML( $returnto ) {
$createAccountData = $this->buildCreateAccountData( $returnto );
$createAccountData['single-id'] = 'pt-createaccount';
$createAccountData['class'] = 'mw-ui-button mw-ui-quiet';
$htmlCreateAccount = $this->makeLink( 'create-account', $createAccountData );
return $htmlCreateAccount;
}
/**
* Returns HTML for the login button and learn more link inside the anon user menu
* @param string[] $returnto array of query strings used to build the login link
* @param bool $useCombinedLoginLink if a combined login/signup link will be used
* @return string
*/
private function getLoginHTML( $returnto, $useCombinedLoginLink ) {
// 'single-id' must be provided for `makeLink` to populate `title`, `accesskey` and other attributes
$loginData = $this->buildLoginData( $returnto, $useCombinedLoginLink );
$loginData['single-id'] = 'pt-login';
$loginData['class'] = 'vector-menu-content-item';
$learnMoreLinkData = [
'text' => $this->msg( 'vector-anon-user-menu-pages-learn' )->text(),
'href' => Title::newFromText( 'Help:Introduction' )->getLocalURL(),
];
$learnMoreLink = $this->makeLink( '', $learnMoreLinkData );
$templateParser = $this->getTemplateParser();
return $templateParser->processTemplate( 'UserLinks__login', [
'htmlLogin' => $this->makeLink( 'login', $loginData ),
'msgLearnMore' => $this->msg( 'vector-anon-user-menu-pages' ),
'htmlLearnMoreLink' => $this->msg( 'parentheses' )->
rawParams( $learnMoreLink )->
escaped()
] );
}
/**
* Returns HTML for the logout button that should be placed in the user (personal) menu
* after the menu itself.
* @return string
*/
private function getLogoutHTML() {
$logoutLinkData = $this->buildLogoutLinkData();
$templateParser = $this->getTemplateParser();
$logoutLinkData['class'] = [
'vector-menu-content-item',
'mw-ui-icon mw-ui-icon-before',
'mw-ui-icon-wikimedia-logOut'
];
return $templateParser->processTemplate( 'UserLinks__logout', [
'htmlLogout' => $this->makeLink( 'logout', $logoutLinkData )
] );
}
/**
* Returns template data for UserLinks.mustache
* @param array $menuData existing menu template data to be transformed and copied for UserLinks
* @param bool $isAnon if the user is logged out, used to conditionally provide data
* @return array
*/
private function getUserLinksTemplateData( $menuData, $isAnon ) : array {
$returnto = $this->getReturnToParam();
$useCombinedLoginLink = $this->useCombinedLoginLink();
$htmlCreateAccount = $this->getCreateAccountHTML( $returnto );
$userMenuData = $menuData[ 'data-user-menu' ];
if ( $isAnon ) {
$userMenuData[ 'html-before-portal' ] .= $this->getLoginHTML( $returnto, $useCombinedLoginLink );
} else {
// Appending as to not override data potentially set by the onSkinAfterPortlet hook.
$userMenuData[ 'html-after-portal' ] .= $this->getLogoutHTML();
}
return [
'is-anon' => $isAnon,
'html-create-account' => $htmlCreateAccount,
'data-user-interface-preferences' => $menuData[ 'data-user-interface-preferences' ],
'data-notifications' => $menuData[ 'data-notifications' ],
'data-user-page' => $menuData[ 'data-user-page' ],
'data-user-menu' => $userMenuData
];
}
/**
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
* @inheritDoc
*/
Merge SkinVector and VectorTemplate (step 1/2) Please note I7e06a4cc226f3434c0f655212a464b8b98bcc7f4 should be merged at the same time as this patch. == The background == All extensions have been weaned of BaseTemplate hooks in Wikimedia projects. This change now means that Vector will no longer run any BaseTemplate hooks. See the epic T253809 for the implementation details. == The change == BaseTemplate will now have nothing to do with the rendering of Vector. The skin version is added to express the significance of breaking compatibility with 3rd party extensions. We TEMPORARILY remove SkinVector to retain git blame. SkinTemplateVector will be renamed SkinVector in the follow up (see 2/2) Update skin.json to use SkinTemplateVector for the skin (this will be fixed in a follow up). The isLegacy method is moved to SkinTemplateVector. Changes of note: * html-debuglog is no longer needed. SkinMustache includes this information on the skins behalf * html-printtail and html-headelement are now not needed in the master template and added by SkinMustache * Skin::getAfterPortlet does not provide the `after-portlet` wrapping element provided by BaseTemplate::getAfterPortlet so this is added * SkinTemplate::getFooterIcons does not support the options that BaseTemplate::getFooterIcons does so any icons which do not have an image must be manually checked for and unset Known changes to HTML output as a result of intentionally delegating their output to the core SkinMustache class: * A new line is removed between the body element and #mw-page-base * #mw-html-debug-log now appears at the end of the body element * #printfooter is now a child of #mw-content-text rather than sibling. Bug: T251212 Change-Id: I4e89beb96f6401ed7e51bafdf0aac408f5a2c42f
2020-04-28 21:16:21 +00:00
public function getTemplateData() : array {
$skin = $this;
$out = $skin->getOutput();
$title = $out->getTitle();
$parentData = parent::getTemplateData();
if ( $this->shouldHideLanguages() ) {
$parentData['data-portlets']['data-languages'] = null;
}
// Naming conventions for Mustache parameters.
//
// Value type (first segment):
// - Prefix "is" or "has" for boolean values.
// - Prefix "msg-" for interface message text.
// - Prefix "html-" for raw HTML.
// - Prefix "data-" for an array of template parameters that should be passed directly
// to a template partial.
// - Prefix "array-" for lists of any values.
//
// Source of value (first or second segment)
// - Segment "page-" for data relating to the current page (e.g. Title, WikiPage, or OutputPage).
// - Segment "hook-" for any thing generated from a hook.
// It should be followed by the name of the hook in hyphenated lowercase.
//
// Conditionally used values must use null to indicate absence (not false or '').
$commonSkinData = array_merge( $parentData, [
'is-consolidated-user-links' => $this->shouldConsolidateUserLinks(),
'is-article' => (bool)$out->isArticle(),
'is-anon' => $this->getUser()->isAnon(),
'is-mainpage' => $title->isMainPage(),
// Remember that the string '0' is a valid title.
// From OutputPage::getPageTitle, via ::setPageTitle().
'html-title' => $out->getPageTitle(),
'html-categories' => $skin->getCategories(),
'input-location' => $this->getSearchBoxInputLocation(),
'sidebar-visible' => $this->isSidebarVisible(),
'is-language-in-header' => $this->isLanguagesInHeader(),
'should-search-expand' => $this->shouldSearchExpand(),
] );
if ( $skin->getUser()->isRegistered() ) {
// Note: This data is also passed to legacy template where it is unused.
$commonSkinData['data-emphasized-sidebar-action'] = [
Add opt-out link to Sidebar for Vector/Logged-in Users Without Abstractions This commit is singularly focused on adding a link to the sidebar for Vector, logged-in users. It does the bare minimum to fulfill the requirements of T243281. Additionally, it will help to answer the question "Do we need to use abstractions (other than maybe different templates) to separate Legacy Vector from Vector" by intentionally leaving out any abstractions in order to make it easier to compare with a follow-up patch (Ib2ef15180df73360cc1de25b893e49d415d23e1a) which does use abstractions. It is a good thing to question whether or not we need addtional abstractions in VectorTemplate and if they will help us as unnecessary abstractions can have the opposite effect and just lead to further frustrations down the road. Therefore, I urge you, the reviewer, to let me know your thoughts! If abstractions are viewed as not making our lives any easier, the follow-up patches may be completely discarded and that's totally okay with me. :) I think it's a good think to talk about now though. Important changes: * The VectorTemplate constructor was changed to allow injecting the config, templateParser, and isLegacy boolean (only the config was allowed before this commit). According to MediaWiki's Stable Interface Policy, "Constructor signatures are generally considered unstable unless explicitly declared stable for calling" [3]. Given that VecorTemplate's constructor is not marked as stable, it is justified to do this without warning according to the policy. * Due to the above, the 'setTemplate' method is no longer needed and was marked as deprecated. * VectorTemplateTest was made to adapt to the new VectorTemplate constructor. Additionally, it now extends from MediaWikiIntegrationTestCase which my intelliphense server can pick up. I *think* MediaWikiTestCase is just an alias to MediaWikiIntegrationTestCase [1] and MediaWikiTestCase file was renamed to MediaWikiIntegrationTestCase in [2], but I'm willing to change it back if there is pushback to this. Open questions: * What are VectorTemplate's responsibilities? To me, it acts right now as a controller (because it echos the full HTML string from the template), a model (because SkinTemplate::prepareQuickTemplate sets data on it which it later retrieves through `$this->get()`), a presenter (because it adds data tailored for a web-centric view), and a view (because it renders HTML strings instead of letting the view/template be solely responsible for that). Arguably, some business logic might be mixed in there as well (because it checks to see if a User is logged in/has necessary permissions to show x which my changes here add to). This might not be a problem if we keep VectorTemplate relatively small, but will it remain this way as we progress further in Desktop Improvements? * How do we write tests for VectorTemplate without exposing unnecessary public methods? For example, if I want to test the `getSkinData()` method to see what state will be sent to the template, how should I do this? One option might be to use `TestingAccessWrapper` to expose these private methods which is what `VectorTemplateTest::testbuildViewsProps()` does. Another option is to accept this method as public. Is there a better way? Keep in mind that even with access to this method, there might be many things to mock. [1] https://github.com/wikimedia/mediawiki/blob/0030cb525be6cabc1d63de80586b2017d4bbe354/tests/common/TestsAutoLoader.php#L64 [2] Ie717b0ecf4fcfd089d46248f14853c80b7ef4a76 [3] https://www.mediawiki.org/wiki/Stable_interface_policy Bug: T243281 Change-Id: I0571b041bcd7f19bec9f103fa7bccdd093f6394d
2020-03-17 20:21:33 +00:00
'href' => SpecialPage::getTitleFor(
'Preferences',
false,
'mw-prefsection-rendering-skin-skin-prefs'
Add opt-out link to Sidebar for Vector/Logged-in Users Without Abstractions This commit is singularly focused on adding a link to the sidebar for Vector, logged-in users. It does the bare minimum to fulfill the requirements of T243281. Additionally, it will help to answer the question "Do we need to use abstractions (other than maybe different templates) to separate Legacy Vector from Vector" by intentionally leaving out any abstractions in order to make it easier to compare with a follow-up patch (Ib2ef15180df73360cc1de25b893e49d415d23e1a) which does use abstractions. It is a good thing to question whether or not we need addtional abstractions in VectorTemplate and if they will help us as unnecessary abstractions can have the opposite effect and just lead to further frustrations down the road. Therefore, I urge you, the reviewer, to let me know your thoughts! If abstractions are viewed as not making our lives any easier, the follow-up patches may be completely discarded and that's totally okay with me. :) I think it's a good think to talk about now though. Important changes: * The VectorTemplate constructor was changed to allow injecting the config, templateParser, and isLegacy boolean (only the config was allowed before this commit). According to MediaWiki's Stable Interface Policy, "Constructor signatures are generally considered unstable unless explicitly declared stable for calling" [3]. Given that VecorTemplate's constructor is not marked as stable, it is justified to do this without warning according to the policy. * Due to the above, the 'setTemplate' method is no longer needed and was marked as deprecated. * VectorTemplateTest was made to adapt to the new VectorTemplate constructor. Additionally, it now extends from MediaWikiIntegrationTestCase which my intelliphense server can pick up. I *think* MediaWikiTestCase is just an alias to MediaWikiIntegrationTestCase [1] and MediaWikiTestCase file was renamed to MediaWikiIntegrationTestCase in [2], but I'm willing to change it back if there is pushback to this. Open questions: * What are VectorTemplate's responsibilities? To me, it acts right now as a controller (because it echos the full HTML string from the template), a model (because SkinTemplate::prepareQuickTemplate sets data on it which it later retrieves through `$this->get()`), a presenter (because it adds data tailored for a web-centric view), and a view (because it renders HTML strings instead of letting the view/template be solely responsible for that). Arguably, some business logic might be mixed in there as well (because it checks to see if a User is logged in/has necessary permissions to show x which my changes here add to). This might not be a problem if we keep VectorTemplate relatively small, but will it remain this way as we progress further in Desktop Improvements? * How do we write tests for VectorTemplate without exposing unnecessary public methods? For example, if I want to test the `getSkinData()` method to see what state will be sent to the template, how should I do this? One option might be to use `TestingAccessWrapper` to expose these private methods which is what `VectorTemplateTest::testbuildViewsProps()` does. Another option is to accept this method as public. Is there a better way? Keep in mind that even with access to this method, there might be many things to mock. [1] https://github.com/wikimedia/mediawiki/blob/0030cb525be6cabc1d63de80586b2017d4bbe354/tests/common/TestsAutoLoader.php#L64 [2] Ie717b0ecf4fcfd089d46248f14853c80b7ef4a76 [3] https://www.mediawiki.org/wiki/Stable_interface_policy Bug: T243281 Change-Id: I0571b041bcd7f19bec9f103fa7bccdd093f6394d
2020-03-17 20:21:33 +00:00
)->getLinkURL( 'wprov=' . self::OPT_OUT_LINK_TRACKING_CODE ),
];
}
if ( $this->shouldConsolidateUserLinks() ) {
$commonSkinData['data-vector-user-links'] = $this->getUserLinksTemplateData(
$commonSkinData['data-portlets'],
$commonSkinData['is-anon']
);
Add opt-out link to Sidebar for Vector/Logged-in Users Without Abstractions This commit is singularly focused on adding a link to the sidebar for Vector, logged-in users. It does the bare minimum to fulfill the requirements of T243281. Additionally, it will help to answer the question "Do we need to use abstractions (other than maybe different templates) to separate Legacy Vector from Vector" by intentionally leaving out any abstractions in order to make it easier to compare with a follow-up patch (Ib2ef15180df73360cc1de25b893e49d415d23e1a) which does use abstractions. It is a good thing to question whether or not we need addtional abstractions in VectorTemplate and if they will help us as unnecessary abstractions can have the opposite effect and just lead to further frustrations down the road. Therefore, I urge you, the reviewer, to let me know your thoughts! If abstractions are viewed as not making our lives any easier, the follow-up patches may be completely discarded and that's totally okay with me. :) I think it's a good think to talk about now though. Important changes: * The VectorTemplate constructor was changed to allow injecting the config, templateParser, and isLegacy boolean (only the config was allowed before this commit). According to MediaWiki's Stable Interface Policy, "Constructor signatures are generally considered unstable unless explicitly declared stable for calling" [3]. Given that VecorTemplate's constructor is not marked as stable, it is justified to do this without warning according to the policy. * Due to the above, the 'setTemplate' method is no longer needed and was marked as deprecated. * VectorTemplateTest was made to adapt to the new VectorTemplate constructor. Additionally, it now extends from MediaWikiIntegrationTestCase which my intelliphense server can pick up. I *think* MediaWikiTestCase is just an alias to MediaWikiIntegrationTestCase [1] and MediaWikiTestCase file was renamed to MediaWikiIntegrationTestCase in [2], but I'm willing to change it back if there is pushback to this. Open questions: * What are VectorTemplate's responsibilities? To me, it acts right now as a controller (because it echos the full HTML string from the template), a model (because SkinTemplate::prepareQuickTemplate sets data on it which it later retrieves through `$this->get()`), a presenter (because it adds data tailored for a web-centric view), and a view (because it renders HTML strings instead of letting the view/template be solely responsible for that). Arguably, some business logic might be mixed in there as well (because it checks to see if a User is logged in/has necessary permissions to show x which my changes here add to). This might not be a problem if we keep VectorTemplate relatively small, but will it remain this way as we progress further in Desktop Improvements? * How do we write tests for VectorTemplate without exposing unnecessary public methods? For example, if I want to test the `getSkinData()` method to see what state will be sent to the template, how should I do this? One option might be to use `TestingAccessWrapper` to expose these private methods which is what `VectorTemplateTest::testbuildViewsProps()` does. Another option is to accept this method as public. Is there a better way? Keep in mind that even with access to this method, there might be many things to mock. [1] https://github.com/wikimedia/mediawiki/blob/0030cb525be6cabc1d63de80586b2017d4bbe354/tests/common/TestsAutoLoader.php#L64 [2] Ie717b0ecf4fcfd089d46248f14853c80b7ef4a76 [3] https://www.mediawiki.org/wiki/Stable_interface_policy Bug: T243281 Change-Id: I0571b041bcd7f19bec9f103fa7bccdd093f6394d
2020-03-17 20:21:33 +00:00
}
return $commonSkinData;
}
/**
* Gets the value of the "input-location" parameter for the SearchBox Mustache template.
*
* @return string Either `Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT` or
* `Constants::SEARCH_BOX_INPUT_LOCATION_MOVED`
*/
private function getSearchBoxInputLocation() : string {
if ( $this->isLegacy() ) {
return Constants::SEARCH_BOX_INPUT_LOCATION_DEFAULT;
}
return Constants::SEARCH_BOX_INPUT_LOCATION_MOVED;
}
/**
* Determines whether or not the search input should expand when focused
* before WVUI search is loaded. In WVUI, the search input expands to
* accomodate thumbnails in the suggestion list. When thumbnails are
* disabled, the input should not expand. Note this is only relevant for WVUI
* search (not legacy search).
*
* @return bool
*/
private function shouldSearchExpand() : bool {
$featureManager = VectorServices::getFeatureManager();
return $featureManager->isFeatureEnabled( Constants::FEATURE_USE_WVUI_SEARCH ) &&
$this->getConfig()->get( 'VectorWvuiSearchOptions' )['showThumbnail'];
}
/**
* Determines wheather the initial state of sidebar is visible on not
*
* @return bool
*/
private function isSidebarVisible() {
$skin = $this->getSkin();
if ( $skin->getUser()->isRegistered() ) {
$userPrefSidebarState = $skin->getUser()->getOption(
Constants::PREF_KEY_SIDEBAR_VISIBLE
);
$defaultLoggedinSidebarState = $this->getConfig()->get(
Constants::CONFIG_KEY_DEFAULT_SIDEBAR_VISIBLE_FOR_AUTHORISED_USER
);
// If the sidebar user preference has been set, return that value,
// if not, then the default sidebar state for logged-in users.
return ( $userPrefSidebarState !== null )
? (bool)$userPrefSidebarState
: $defaultLoggedinSidebarState;
}
return $this->getConfig()->get(
Constants::CONFIG_KEY_DEFAULT_SIDEBAR_VISIBLE_FOR_ANONYMOUS_USER
);
}
/**
* Combines class and other HTML data required to create the button
* for the languages in header feature with the existing language portletData.
*
* @param array $portletData returned by SkinMustache
* @return array enhanced $portletData
*/
private function createULSLanguageButton( $portletData ) {
$languageButtonData = [
'id' => 'p-lang-btn',
'label' => $this->msg(
'vector-language-button-label',
count( $this->getLanguagesCached() )
)->escaped(),
'heading-class' =>
' vector-menu-heading ' .
' mw-ui-icon ' .
' mw-ui-icon-before ' .
' mw-ui-icon-wikimedia-language ' .
' mw-ui-button mw-ui-quiet ' .
// ext.uls.interface attaches click handler to this selector.
' mw-interlanguage-selector ',
];
return array_merge( $portletData, $languageButtonData );
}
/**
* helper for applying Vector menu classes to portlets
* @param array $portletData returned by SkinMustache to decorate
* @param int $type representing one of the menu types (see MENU_TYPE_* constants)
* @return array modified version of portletData input
*/
private function decoratePortletClass(
array $portletData,
int $type = self::MENU_TYPE_DEFAULT
) {
$extraClasses = [
self::MENU_TYPE_DROPDOWN => 'vector-menu vector-menu-dropdown',
self::MENU_TYPE_TABS => 'vector-menu vector-menu-tabs',
self::MENU_TYPE_PORTAL => 'vector-menu vector-menu-portal portal',
self::MENU_TYPE_DEFAULT => 'vector-menu',
];
$portletData['heading-class'] = 'vector-menu-heading';
// Add target class to apply different icon to personal menu dropdown for logged in users.
if ( $portletData['id'] === 'p-personal' ) {
if ( $this->shouldConsolidateUserLinks() ) {
$portletData['class'] .= ' vector-user-menu';
// Replace dropdown arrow with ellipsis icon if feature flag is enabled and user is logged in.
$portletData['heading-class'] .= ' mw-ui-icon mw-ui-icon-element mw-ui-icon-wikimedia-ellipsis';
} else {
$portletData['class'] .= ' vector-user-menu-legacy';
}
}
if ( $portletData['id'] === 'p-lang' && $this->isLanguagesInHeader() ) {
$portletData = $this->createULSLanguageButton( $portletData );
}
$class = $portletData['class'];
$portletData['class'] = trim( "$class $extraClasses[$type]" );
return $portletData;
}
/**
* @inheritDoc
* @return array
*/
protected function getPortletData(
$label,
array $urls = []
) : array {
switch ( $label ) {
case 'user-menu':
$type = $this->shouldConsolidateUserLinks() ? self::MENU_TYPE_DROPDOWN : self::MENU_TYPE_DEFAULT;
break;
case 'actions':
case 'variants':
$type = self::MENU_TYPE_DROPDOWN;
break;
case 'views':
case 'namespaces':
$type = self::MENU_TYPE_TABS;
break;
case 'notifications':
case 'personal':
case 'user-page':
$type = self::MENU_TYPE_DEFAULT;
break;
case 'lang':
$type = $this->isLanguagesInHeader() ?
self::MENU_TYPE_DROPDOWN : self::MENU_TYPE_PORTAL;
break;
default:
$type = self::MENU_TYPE_PORTAL;
break;
}
$portletData = $this->decoratePortletClass(
parent::getPortletData( $label, $urls ),
$type
);
// Special casing for Variant to change label to selected.
// Hopefully we can revisit and possibly remove this code when the language switcher is moved.
if ( $label === 'variants' ) {
foreach ( $urls as $key => $item ) {
// Check the class of the item for a `selected` class and if so, propagate the items
// label to the main label.
if ( isset( $item['class'] ) && stripos( $item['class'], 'selected' ) !== false ) {
$portletData['label'] = $item['text'];
}
}
}
return $portletData + [
'is-dropdown' => $type === self::MENU_TYPE_DROPDOWN,
];
}
}