mediawiki-skins-Citizen/resources/skins.citizen.scripts/echo.js
alistair3149 fdc6eaee20
feat(Echo): upgrade Echo buttons for consistency
This is similiar to how it is handled in Vector.
We are forcing the Echo button to render in the same way as it was initially.
This took me so many hours sigh.
2024-07-05 20:37:52 -04:00

108 lines
3.4 KiB
JavaScript

/**
* Originally based on Vector
*
* Upgrades Echo for icon consistency.
* Undos work inside Echo to replace our button.
*
* TODO: Switch to mw.hook( 'ext.echo.NotificationBadgeWidget.onInitialize' ) when we drop 1.39 support
*/
function init() {
if ( document.querySelectorAll( '#pt-notifications-alert a, #pt-notifications-notice a' ).length !== 2 ) {
return;
}
const notifications = document.getElementById( 'p-notifications' );
// Clone the icons so we can insert it back afterwards
const alertIcon = notifications.querySelector( '#pt-notifications-alert > a > .citizen-ui-icon' ).cloneNode();
const noticeIcon = notifications.querySelector( '#pt-notifications-notice > a > .citizen-ui-icon' ).cloneNode();
// When the Echo button is clicked, all of its children are reset back to the initial state.
// This will re-upgrade the children of the Echo button
const callChildSupportServices = ( anchor ) => {
const badge = anchor.parentElement;
// Wrap label in a span
const label = document.createElement( 'span' );
label.textContent = anchor.textContent;
anchor.replaceChildren( label );
// Add icon span back
if ( badge.id === 'pt-notifications-alert' ) {
anchor.prepend( alertIcon );
anchor.classList.remove( 'oo-ui-icon-bell' );
} else if ( badge.id === 'pt-notifications-notice' ) {
anchor.prepend( noticeIcon );
anchor.classList.remove( 'oo-ui-icon-tray' );
}
};
// Upgrade the Echo badge
// This only needs to be run once at the Echo button init
const setupFosterHome = ( badge, anchor ) => {
badge.classList.add( 'mw-list-item' );
anchor.classList.remove( 'mw-echo-notifications-badge' );
anchor.classList.add( 'citizen-header__button', 'citizen-echo-notification-badge' );
callChildSupportServices( anchor );
};
// Whenever Echo kicks its children out from the button, undo what Echo did.
const abuseObserver = new MutationObserver( ( mutations ) => {
for ( const mutation of mutations ) {
if ( mutation.type === 'childList' ) {
const removedNodes = mutation.removedNodes;
if ( removedNodes.length === 0 ) {
return;
}
for ( const removedNode of removedNodes ) {
if ( !( removedNode instanceof HTMLSpanElement ) || !removedNode.classList.contains( 'citizen-ui-icon' ) ) {
return;
}
const anchor = mutation.target;
callChildSupportServices( anchor );
}
}
}
} );
// Observe for Echo button init, it will only happen once per icon (so twice)
let initObserved = 0;
const initObserver = new MutationObserver( ( mutations ) => {
for ( const mutation of mutations ) {
// All Echo buttons are observed by abuseObserver, disconnect observer.
if ( initObserved >= 2 ) {
initObserver.disconnect();
}
if ( mutation.type === 'childList' ) {
const addedNodes = mutation.addedNodes;
if ( addedNodes.length === 0 ) {
return;
}
for ( const addedNode of addedNodes ) {
if ( !addedNode.classList.contains( 'mw-echo-ui-notificationBadgeButtonPopupWidget' ) ) {
return;
}
const anchor = addedNode.firstElementChild;
// Upgrade the badge immediately before Echo kicks its children out
setupFosterHome( addedNode, anchor );
// Observe Echo button
abuseObserver.observe(
anchor,
{
childList: true,
subtree: true
}
);
initObserved++;
}
}
}
} );
initObserver.observe(
notifications,
{
childList: true,
subtree: true
}
);
}
module.exports = init;