mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-27 17:10:19 +00:00
Consolidate watchstar icon updating logic under watchstar.js
Depends-on: Ib11177df52d46ecda2ace50ac78672ed3d5fd5c9 Bug: T336640 Bug: T336641 Change-Id: If2573409cd1af4580f89b33c32cd0441e7a80735
This commit is contained in:
parent
440843d84c
commit
27e821a486
|
@ -9,26 +9,22 @@ use MessageLocalizer;
|
|||
*/
|
||||
class VectorComponentStickyHeader implements VectorComponent {
|
||||
private const TALK_ICON = [
|
||||
'label' => '',
|
||||
'icon' => 'speechBubbles',
|
||||
'id' => 'ca-talk-sticky-header',
|
||||
'event' => 'talk-sticky-header'
|
||||
];
|
||||
private const SUBJECT_ICON = [
|
||||
'label' => '',
|
||||
'icon' => 'article',
|
||||
'id' => 'ca-subject-sticky-header',
|
||||
'event' => 'subject-sticky-header'
|
||||
];
|
||||
private const HISTORY_ICON = [
|
||||
'label' => '',
|
||||
'icon' => 'wikimedia-history',
|
||||
'id' => 'ca-history-sticky-header',
|
||||
'event' => 'history-sticky-header',
|
||||
];
|
||||
// Event and icon will be updated depending on watchstar state
|
||||
private const WATCHSTAR_ICON = [
|
||||
'label' => '',
|
||||
'id' => 'ca-watchstar-sticky-header',
|
||||
'event' => 'watch-sticky-header',
|
||||
'icon' => 'wikimedia-star',
|
||||
|
@ -40,19 +36,16 @@ class VectorComponentStickyHeader implements VectorComponent {
|
|||
'class' => 'mw-watchlink'
|
||||
];
|
||||
private const EDIT_VE_ICON = [
|
||||
'label' => '',
|
||||
'id' => 'ca-ve-edit-sticky-header',
|
||||
'event' => 've-edit-sticky-header',
|
||||
'icon' => 'wikimedia-edit',
|
||||
];
|
||||
private const EDIT_WIKITEXT_ICON = [
|
||||
'label' => '',
|
||||
'id' => 'ca-edit-sticky-header',
|
||||
'event' => 'wikitext-edit-sticky-header',
|
||||
'icon' => 'wikimedia-wikiText',
|
||||
];
|
||||
private const EDIT_PROTECTED_ICON = [
|
||||
'label' => '',
|
||||
'href' => '#',
|
||||
'id' => 'ca-viewsource-sticky-header',
|
||||
'event' => 've-edit-protected-sticky-header',
|
||||
|
@ -114,7 +107,8 @@ class VectorComponentStickyHeader implements VectorComponent {
|
|||
$iconButtons = [];
|
||||
foreach ( $icons as $icon ) {
|
||||
$iconButtons[] = new VectorComponentButton(
|
||||
$icon[ 'label' ],
|
||||
// Button labels will be populated in stickyHeader.js
|
||||
"",
|
||||
$icon[ 'icon' ],
|
||||
$icon[ 'id' ],
|
||||
$icon[ 'class' ] ?? '',
|
||||
|
|
|
@ -7,7 +7,7 @@ const languageButton = require( './languageButton.js' ),
|
|||
ABTestConfig = require( /** @type {string} */ ( './activeABTest.json' ) ),
|
||||
initSearchLoader = require( './searchLoader.js' ).initSearchLoader,
|
||||
dropdownMenus = require( './dropdownMenus.js' ).dropdownMenus,
|
||||
watchstar = require( './watchstar.js' ),
|
||||
watchstar = require( './watchstar.js' ).init,
|
||||
setupIntersectionObservers = require( './setupIntersectionObservers.js' ),
|
||||
menuTabs = require( './menuTabs.js' );
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
const
|
||||
initSearchToggle = require( './searchToggle.js' ),
|
||||
updateWatchIcon = require( './watchstar.js' ).updateWatchIcon,
|
||||
STICKY_HEADER_ID = 'vector-sticky-header',
|
||||
STICKY_HEADER_APPENDED_ID = '-sticky-header',
|
||||
STICKY_HEADER_APPENDED_PARAM = [ 'wvprov', 'sticky-header' ],
|
||||
|
@ -55,6 +56,10 @@ function hide() {
|
|||
function copyButtonAttributes( from, to ) {
|
||||
copyAttribute( from, to, 'href' );
|
||||
copyAttribute( from, to, 'title' );
|
||||
// Copy button labels
|
||||
if ( to.lastElementChild && from.lastElementChild ) {
|
||||
to.lastElementChild.innerHTML = from.lastElementChild.textContent || '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,6 +125,16 @@ function removeNode( node ) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures a sticky header button has the correct attributes
|
||||
*
|
||||
* @param {Element} watchLink
|
||||
* @param {boolean} isWatched The page is watched
|
||||
*/
|
||||
function updateStickyWatchlink( watchLink, isWatched ) {
|
||||
watchLink.setAttribute( 'data-event-name', isWatched ? 'watch-sticky-header' : 'unwatch-sticky-header' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NodeList} nodes
|
||||
* @param {string} className
|
||||
|
@ -139,32 +154,14 @@ function removeNodes( nodes ) {
|
|||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures a sticky header button has the correct attributes
|
||||
*
|
||||
* @param {Element} watchSticky
|
||||
* @param {string} status 'watched', 'unwatched', or 'temporary'
|
||||
*/
|
||||
function updateStickyWatchlink( watchSticky, status ) {
|
||||
watchSticky.classList.toggle( 'mw-ui-icon-wikimedia-star', status === 'unwatched' );
|
||||
watchSticky.classList.toggle( 'mw-ui-icon-wikimedia-unStar', status === 'watched' );
|
||||
watchSticky.classList.toggle( 'mw-ui-icon-wikimedia-halfStar', status === 'temporary' );
|
||||
watchSticky.setAttribute( 'data-event-name', status === 'unwatched' ? 'watch-sticky-header' : 'unwatch-sticky-header' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for watchsar
|
||||
*
|
||||
* @param {JQuery} $link Watchstar link
|
||||
* @param {boolean} isWatched The page is watched
|
||||
* @param {string} [expiry] Optional expiry time
|
||||
*/
|
||||
function watchstarCallback( $link, isWatched, expiry ) {
|
||||
updateStickyWatchlink(
|
||||
/** @type {HTMLAnchorElement} */( $link[ 0 ] ),
|
||||
expiry !== 'infinity' ? 'temporary' :
|
||||
isWatched ? 'watched' : 'unwatched'
|
||||
);
|
||||
function watchstarCallback( $link, isWatched ) {
|
||||
updateStickyWatchlink( /** @type {HTMLAnchorElement} */( $link[ 0 ] ), isWatched );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,12 +203,14 @@ function prepareIcons( header, history, talk, subject, watch ) {
|
|||
|
||||
if ( watch && watch.parentNode instanceof Element ) {
|
||||
const watchContainer = watch.parentNode;
|
||||
const isTemporaryWatch = watchContainer.classList.contains( 'mw-watchlink-temp' );
|
||||
const isWatched = isTemporaryWatch || watchContainer.getAttribute( 'id' ) === 'ca-unwatch';
|
||||
const watchIcon = /** @type {HTMLElement} */ ( watchSticky.querySelector( '.mw-ui-icon' ) );
|
||||
|
||||
// Initialize sticky watchlink
|
||||
copyButtonAttributes( watch, watchSticky );
|
||||
updateStickyWatchlink(
|
||||
watchSticky,
|
||||
watchContainer.classList.contains( 'mw-watchlink-temp' ) ? 'temporary' :
|
||||
watchContainer.getAttribute( 'id' ) === 'ca-watch' ? 'unwatched' : 'watched'
|
||||
);
|
||||
updateWatchIcon( watchIcon, isWatched, isTemporaryWatch ? '' : 'infinity' );
|
||||
updateStickyWatchlink( watchSticky, isWatched );
|
||||
|
||||
const watchLib = require( /** @type {string} */( 'mediawiki.page.watch.ajax' ) );
|
||||
watchLib.watchstar( $( watchSticky ), mw.config.get( 'wgRelevantPageName' ), watchstarCallback );
|
||||
|
|
|
@ -1,30 +1,45 @@
|
|||
module.exports = function () {
|
||||
/**
|
||||
* @param {HTMLElement} watchIcon
|
||||
* @param {boolean} isWatched
|
||||
* @param {string} expiry
|
||||
*/
|
||||
const updateWatchIcon = ( watchIcon, isWatched, expiry ) => {
|
||||
watchIcon.classList.remove(
|
||||
// Vector attaches two icon classes to the element.
|
||||
// Remove the mw-ui-icon one rather than managing both.
|
||||
'mw-ui-icon-star',
|
||||
'mw-ui-icon-unStar',
|
||||
'mw-ui-icon-wikimedia-unStar',
|
||||
'mw-ui-icon-wikimedia-star',
|
||||
'mw-ui-icon-wikimedia-halfStar'
|
||||
);
|
||||
|
||||
if ( isWatched ) {
|
||||
if ( expiry === 'infinity' ) {
|
||||
watchIcon.classList.add( 'mw-ui-icon-wikimedia-unStar' );
|
||||
} else {
|
||||
watchIcon.classList.add( 'mw-ui-icon-wikimedia-halfStar' );
|
||||
}
|
||||
} else {
|
||||
watchIcon.classList.add( 'mw-ui-icon-wikimedia-star' );
|
||||
}
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
mw.hook( 'wikipage.watchlistChange' ).add(
|
||||
function ( /** @type {boolean} */ isWatched, /** @type {string} */ expiry ) {
|
||||
const watchIcon = document.querySelectorAll( '#ca-watch .mw-ui-icon, #ca-unwatch .mw-ui-icon' )[ 0 ];
|
||||
if ( !watchIcon ) {
|
||||
const watchIcons = document.querySelectorAll( '.mw-watchlink .mw-ui-icon' );
|
||||
if ( !watchIcons ) {
|
||||
return;
|
||||
}
|
||||
|
||||
watchIcon.classList.remove(
|
||||
// Vector attaches two icon classes to the element.
|
||||
// Remove the mw-ui-icon one rather than managing both.
|
||||
'mw-ui-icon-star',
|
||||
'mw-ui-icon-unStar',
|
||||
'mw-ui-icon-wikimedia-unStar',
|
||||
'mw-ui-icon-wikimedia-star',
|
||||
'mw-ui-icon-wikimedia-halfStar'
|
||||
);
|
||||
|
||||
if ( isWatched ) {
|
||||
if ( expiry === 'infinity' ) {
|
||||
watchIcon.classList.add( 'mw-ui-icon-wikimedia-unStar' );
|
||||
} else {
|
||||
watchIcon.classList.add( 'mw-ui-icon-wikimedia-halfStar' );
|
||||
}
|
||||
} else {
|
||||
watchIcon.classList.add( 'mw-ui-icon-wikimedia-star' );
|
||||
}
|
||||
Array.from( watchIcons ).forEach( ( watchIcon ) => {
|
||||
updateWatchIcon( /** @type {HTMLElement} */ ( watchIcon ), isWatched, expiry );
|
||||
} );
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
updateWatchIcon,
|
||||
init
|
||||
};
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
* (in which case it is inside `.vector-menu-dropdown` instead of `.vector-menu-tabs`). */
|
||||
// Note: there's no watchstar for anon users so no need to worry about cached HTML when changing this class
|
||||
// Loading watchstar link class.
|
||||
.mw-watchlink .mw-ui-icon::before {
|
||||
transition: transform 500ms;
|
||||
}
|
||||
.mw-watchlink {
|
||||
.mw-ui-icon {
|
||||
transition: transform 500ms;
|
||||
}
|
||||
|
||||
.mw-ui-icon-wikimedia-unStar::before {
|
||||
transform: rotate( 72deg );
|
||||
.mw-ui-icon-wikimedia-unStar {
|
||||
transform: rotate( 72deg );
|
||||
}
|
||||
}
|
|
@ -39,7 +39,7 @@
|
|||
@import './components/PageTitlebar.less';
|
||||
@import './components/PageToolbar.less';
|
||||
@import './components/PopupNotification.less';
|
||||
@import './components/TabWatchstarLink.less';
|
||||
@import './components/Watchstar.less';
|
||||
@import './components/Icon.less';
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue