Icons: Watchstar and wikilove are upgraded

Can be tested by appending ?vectorvisualenhancementnext=1
to URL

Bug: T310838
Bug: T234990
Bug: T234550
Depends-On: I76d0d94c9006cc5f5680849ecdd1c382c16e34ba
Depends-On: Ib7c3021db014827b4b88cac855afc0b54a360f8c
Change-Id: Ie2ffa5c3ecf270c1bb1f315937023ae7ace5ed30
This commit is contained in:
Jon Robson 2022-09-02 07:57:31 -07:00 committed by Jdlrobson
parent e629775aff
commit 97cf735de2
7 changed files with 173 additions and 30 deletions

View File

@ -153,7 +153,7 @@ class Hooks implements
}
/**
* Transforms watch item inside the action navigation menu
* Moves watch item from actions to views menu.
*
* @param array &$content_navigation
*/
@ -168,15 +168,60 @@ class Hooks implements
// Promote watch link from actions to views and add an icon
if ( $key !== null ) {
self::appendClassToItem(
$content_navigation['actions'][$key]['class'],
[ 'icon' ]
);
$content_navigation['views'][$key] = $content_navigation['actions'][$key];
unset( $content_navigation['actions'][$key] );
}
}
/**
* Adds icons to items in the "views" menu.
*
* @param array &$content_navigation
* @param bool $isLegacy is this the legacy Vector skin?
*/
private static function updateViewsMenuIcons( &$content_navigation, $isLegacy ) {
$featureManager = VectorServices::getFeatureManager();
$visualEnhancements = $featureManager->isFeatureEnabled( Constants::FEATURE_VISUAL_ENHANCEMENTS );
foreach ( $content_navigation['views'] as $key => $item ) {
$icon = $item['icon'] ?? null;
if ( $icon ) {
if ( $isLegacy || !$featureManager->isFeatureEnabled( Constants::FEATURE_VISUAL_ENHANCEMENTS ) ) {
self::appendClassToItem(
$item['class'],
[ 'icon' ]
);
} else {
// Force the item as a button with hidden text.
$item['button'] = true;
$item['text-hidden'] = true;
$item = self::updateMenuItemData( $item, true );
}
} else {
self::appendClassToItem(
$item['class'],
[ 'vector-tab-noicon' ]
);
}
$content_navigation['views'][$key] = $item;
}
}
/**
* All associated pages menu items do not have icons so are given the vector-tab-noicon class.
*
* @param array &$content_navigation
*/
private static function updateAssociatedPagesMenuIcons( &$content_navigation ) {
foreach ( $content_navigation['associated-pages'] as $key => $item ) {
self::appendClassToItem(
$item['class'],
[ 'vector-tab-noicon' ]
);
$content_navigation['associated-pages'][$key] = $item;
}
}
/**
* Adds class to a property
*
@ -376,9 +421,10 @@ class Hooks implements
* @param array $item data to update
* @param string $buttonClassProp property to append button classes
* @param string $iconHtmlProp property to set icon HTML
* @param bool $isSmallIcon when set a small icon will be applied rather than the standard icon size
* @return array $item Updated data
*/
private static function updateItemData( $item, $buttonClassProp, $iconHtmlProp ) {
private static function updateItemData( $item, $buttonClassProp, $iconHtmlProp, $isSmallIcon = false ) {
$hasButton = $item['button'] ?? false;
$hideText = $item['text-hidden'] ?? false;
$isCollapsible = $item['collapsible'] ?? false;
@ -403,6 +449,9 @@ class Hooks implements
// We should seek to remove all these instances.
'mw-ui-icon-wikimedia-' . $icon
];
if ( $isSmallIcon ) {
$iconElementClasses[] = 'mw-ui-icon-small';
}
self::appendClassToItem( $item[ $buttonClassProp ], $iconElementClasses );
} else {
$item[ $iconHtmlProp ] = self::makeIcon( $icon );
@ -439,12 +488,13 @@ class Hooks implements
* Updates template data for Vector menu items.
*
* @param array $item menu item data to update
* @param bool $isSmallIcon when set a small icon will be applied rather than the standard icon size
* @return array $item Updated menu item data
*/
public static function updateMenuItemData( $item ) {
public static function updateMenuItemData( $item, $isSmallIcon = false ) {
$buttonClassProp = 'link-class';
$iconHtmlProp = 'link-html';
return self::updateItemData( $item, $buttonClassProp, $iconHtmlProp );
return self::updateItemData( $item, $buttonClassProp, $iconHtmlProp, $isSmallIcon );
}
/**
@ -500,19 +550,27 @@ class Hooks implements
$title = $sk->getRelevantTitle();
$skinName = $sk->getSkinName();
if ( self::isVectorSkin( $skinName ) ) {
if (
$sk->getConfig()->get( 'VectorUseIconWatch' ) &&
$title && $title->canExist()
) {
self::updateActionsMenu( $content_navigation );
}
self::updateUserLinksItems( $sk, $content_navigation );
// These changes should only happen in Vector.
if ( !$skinName || !self::isVectorSkin( $skinName ) ) {
return;
}
if (
$sk->getConfig()->get( 'VectorUseIconWatch' ) &&
$title && $title->canExist()
) {
self::updateActionsMenu( $content_navigation );
}
self::updateUserLinksItems( $sk, $content_navigation );
if ( $skinName === Constants::SKIN_NAME_MODERN ) {
self::createMoreOverflowMenu( $content_navigation );
}
// The updating of the views menu happens /after/ the overflow menu has been created
// this avoids icons showing in the more overflow menu.
self::updateViewsMenuIcons( $content_navigation, self::isSkinVersionLegacy( $skinName ) );
self::updateAssociatedPagesMenuIcons( $content_navigation );
}
/**

View File

@ -2,6 +2,7 @@ var languageButton = require( './languageButton.js' ),
initSearchLoader = require( './searchLoader.js' ).initSearchLoader,
dropdownMenus = require( './dropdownMenus.js' ).dropdownMenus,
sidebarPersistence = require( './sidebarPersistence.js' ),
watchstar = require( './watchstar.js' ),
checkbox = require( './checkbox.js' );
/**
@ -74,6 +75,9 @@ function main( window ) {
languageButton();
dropdownMenus();
addNamespacesGadgetSupport();
if ( document.body.classList.contains( 'vector-feature-visual-enhancement-next-enabled' ) ) {
watchstar();
}
}
/**

View File

@ -0,0 +1,24 @@
module.exports = function () {
mw.hook( 'wikipage.watchlistChange' ).add(
function ( /** @type {boolean} */ isWatched, /** @type {string} */ expiry ) {
var watchElement = document.querySelectorAll( '#ca-watch a, #ca-unwatch a' )[ 0 ];
if ( !watchElement ) {
return;
}
watchElement.classList.remove(
'mw-ui-icon-wikimedia-unStar',
'mw-ui-icon-wikimedia-star',
'mw-ui-icon-wikimedia-halfStar'
);
if ( isWatched ) {
if ( expiry === 'infinity' ) {
watchElement.classList.add( 'mw-ui-icon-wikimedia-unStar' );
} else {
watchElement.classList.add( 'mw-ui-icon-wikimedia-halfStar' );
}
} else {
watchElement.classList.add( 'mw-ui-icon-wikimedia-star' );
}
}
);
};

View File

@ -15,8 +15,11 @@
}
/* focus and hover have outlines. Text underline interferes with bottom border */
.mw-list-item a:focus,
.mw-list-item a:hover {
/* FIXME: Remove 2 not selectors when cache has cleared for Ie2ffa5c3ecf270c1bb1f315937023ae7ace5ed30 */
.mw-list-item a:not( .mw-ui-icon ):focus,
.mw-list-item a:not( .mw-ui-icon ):hover,
.mw-list-item.vector-tab-noicon a:focus,
.mw-list-item.vector-tab-noicon a:hover {
text-decoration: none;
border-bottom: @border-width-base @border-style-base;
}
@ -37,11 +40,18 @@
* Tab list item appearance. Applies to both <li>'s inside .vector-menu-tabs
* and dropdown menus inside the article toolbar
*/
// FIXME: Remove the body selector once Ie2ffa5c3ecf270c1bb1f315937023ae7ace5ed30 is in production
/* for cached HTML */ body:not( .vector-feature-visual-enhancement-next-enabled ) .vector-menu-tabs .mw-list-item,
.vector-menu-tabs .mw-list-item.vector-tab-noicon,
.mw-article-toolbar-container .vector-menu-dropdown {
margin: 0 @padding-horizontal-tabs;
}
.vector-menu-tabs .mw-list-item,
.mw-article-toolbar-container .vector-menu-dropdown {
float: left;
white-space: nowrap;
margin: 0 @padding-horizontal-tabs;
margin-bottom: 0; /* overrides default `li` styling */
// target links inside of .vector-tab-menu
// and dropdown menu headings inside the article toolbar.
@ -51,19 +61,42 @@
.vector-menu-heading {
display: inline-flex;
position: relative;
// Top & bottom padding to increase clickable area.
padding: 18px 0 7px 0;
// bottom margin to overlap border with toolbar border.
margin-bottom: -1px;
cursor: pointer;
border-bottom: @border-width-base @border-style-base transparent;
// max-height & box-sizing to make link, watchstar & dropdown height consistent.
// NOTE: Was 40px instead of 41, but changed to avoid visual regressions.
max-height: unit( 41 / @font-size-tabs / @font-size-browser, em );
box-sizing: border-box;
font-weight: normal;
}
.vector-menu-heading {
// For better compatibility with gadgets (like Twinkle) that append
// <H3> elements as dropdown headings (which was the convention in legacy Vector).
font-size: inherit;
font-weight: normal;
}
/* FIXME: Remove cached HTML selector (> a:not( .mw-ui-icon ))
when Ie2ffa5c3ecf270c1bb1f315937023ae7ace5ed30 is in production */
&.vector-tab-noicon > a,
& > a:not( .mw-ui-icon ),
.vector-menu-heading {
// Top & bottom padding to increase clickable area.
padding: 18px 0 7px 0;
// bottom margin to overlap border with toolbar border.
margin-bottom: -1px;
}
}
// With mw-ui-icons, expand watchstar and wikilove links it to cover full touch area
.vector-feature-visual-enhancement-next-enabled {
.vector-menu-tabs {
.mw-list-item {
.mw-ui-icon {
// Align small icons with the bottom of the tabs.
// Height of tab is 41px, and small icon is 36px,
// With 1px border, 41 - 36 + 1;
margin: 4px 0 0 0;
}
}
}
}

View File

@ -5,7 +5,8 @@
/* Watch/Unwatch Icon Styling */
/* Only use icon if the menu item is not collapsed into the "More" dropdown
* (in which case it is inside `.vector-menu-dropdown` instead of `.vector-menu-tabs`). */
.vector-menu-tabs {
// Note: there's no watchstar for anon users so no need to worry about cached HTML when changing this class
.vector-feature-visual-enhancement-next-disabled .vector-menu-tabs {
@size-watchlink-icon: unit( 16 / @font-size-tabs / @font-size-browser, em );
.mw-watchlink.icon a {
@ -59,3 +60,15 @@
transform-origin: 50% 50%;
}
}
// Loading watchstar link class.
.vector-feature-visual-enhancement-next-enabled {
.mw-watchlink .loading:before {
.rotation( 500ms );
/* Suppress the hilarious rotating focus outline on Firefox */
outline: 0;
cursor: default;
pointer-events: none;
transform-origin: 50% 50%;
}
}

View File

@ -311,6 +311,7 @@
}
},
"icons": [
"heart",
"language",
"ellipsis",
"userAvatar",
@ -387,6 +388,7 @@
"name": "resources/skins.vector.js/config.json",
"callback": "MediaWiki\\Skins\\Vector\\Hooks::getVectorResourceLoaderConfig"
},
"resources/skins.vector.js/watchstar.js",
"resources/skins.vector.js/dropdownMenus.js",
"resources/skins.vector.js/checkbox.js",
"resources/skins.vector.js/sidebarPersistence.js",

View File

@ -394,19 +394,24 @@ class VectorHooksTest extends MediaWikiIntegrationTestCase {
*/
public function testOnSkinTemplateNavigation() {
$this->setMwGlobals( [
'wgVectorUseIconWatch' => true
'wgVectorUseIconWatch' => true,
'wgVectorVisualEnhancementNext' => false,
] );
$skin = new SkinVector22( [ 'name' => 'vector' ] );
$skin->getContext()->setTitle( Title::newFromText( 'Foo' ) );
$contentNavWatch = [
'associated-pages' => [],
'views' => [],
'actions' => [
'watch' => [ 'class' => [ 'watch' ] ],
'watch' => [ 'class' => [ 'watch' ], 'icon' => 'star' ],
]
];
$contentNavUnWatch = [
'associated-pages' => [],
'views' => [],
'actions' => [
'move' => [ 'class' => [ 'move' ] ],
'unwatch' => [],
'unwatch' => [ 'icon' => 'unStar' ],
],
];
@ -433,6 +438,8 @@ class VectorHooksTest extends MediaWikiIntegrationTestCase {
public function testUpdateUserLinksItems() {
$vector2022Skin = new SkinVector22( [ 'name' => 'vector-2022' ] );
$contentNav = [
'associated-pages' => [],
'views' => [],
'user-page' => [
'userpage' => [ 'class' => [], 'icon' => 'userpage' ],
],
@ -442,6 +449,8 @@ class VectorHooksTest extends MediaWikiIntegrationTestCase {
];
$vectorLegacySkin = new SkinVectorLegacy( [ 'name' => 'vector' ] );
$contentNavLegacy = [
'associated-pages' => [],
'views' => [],
'user-page' => [
'userpage' => [ 'class' => [], 'icon' => 'userpage' ],
]