User:Aaron Liu/Watchlyst Greybar Unsin.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* Watchlyst Greybar Unsin ([[User:Aaron Liu/Watchlyst Greybar Unsin.js]]) 3.1.4 */
/* eslint-disable no-undef */// since some other script defined api as a var
// <syntaxhighlight lang="js">

// utility function that adds CSS so that user can easily override it
function addCss( style ) {
	mw.loader.addStyleTag( style, document.head.children[ 0 ] );
}

// non-talk namespaces have an even number
if ( mw.config.get( 'wgNamespaceNumber' ) % 2 === 0 && mw.config.get( 'action' ) !== 'history' ) {
	// non-talk, non-history and non-watchlist pages don't have this style for some reason
	addCss( '.autocomment,.autocomment a,.autocomment a:visited{color:#72777d}' );
}

function getWatchlyst( data ) {
	// Don't display if no new watchlist items or if you're on the watchlist page
	if ( data.query.watchlist.length !== 0 && mw.config.get( 'wgPageName' ) !== 'Special:Watchlist' ) {
		data = data.query.watchlist[ 0 ];

		const summary = data.parsedcomment
			.replaceAll( '&lt;', '<' ).replaceAll( '&gt;', '>' ).replaceAll( '&quot;', '"' ); // might edit under categorization
		const user = '<a href="' + mw.util.getUrl( data.anon ? 'Special:Contributions/' : 'User:' + data.user ) + '">' + data.user + '</a>';
		const $dismiss = $( '<button>' ).attr( 'id', 'watchlystDismiss' ).addClass( 'dismissButton' ).text( 'dismiss' )
			.on( 'click', () => refreshWatchlyst( data.title, data.timestamp ) );
		switch ( data.type ) {
			case 'new':
			case 'edit': {
				const changed = data.type === 'edit' ? 'edited' : ( data.type === 'new' ? 'created' : 'changed' );
				const page = data.title;

				return $( '<span>' +
                    '"<a class="mw-changeslist-title" href="' + mw.util.getUrl( page ) + '">' + page + '</a>' +
                    '" ' + changed + ' by ' + user + ( summary.length === 0 ? '' : ': "' + summary + '"' ) +
                    '. (<a class="mw-changeslist-diff" href="' + mw.util.getUrl( page, { diff: data.revid } ) + '">diff</a>' +
                    ', <a class="mw-changeslist-hist" href="' + mw.util.getUrl( page, { action: 'history' } ) + '">hist</a>' +
                    ', <a class="mw-changeslist-watchlist" href="' + mw.util.getUrl( 'Special:Watchlist' ) + '">watchlist</a>) </span>' )
					.append( $dismiss );
			}
			case 'categorize': {
				const page = data.title;
				summary.replace( ' category', ' <a class="mw-changelist-title" href="' + mw.util.getUrl( page ) + '">' + page + ' by ' + user );
			}
			// so that we can reuse the same code...
			/* fall through */
			default:
				// categorize and log have quite similar formats, so I think external also does.
				// tell me if you encounter it
				return $( '<span>' +
                    data.logdisplay.replace( '&lt;', '<' ).replace( '&gt;', '>' ).replace( '&quot;', '"' ) +
                    ( summary.length === 0 ? '' : ': "' + summary + '"' ) +
                    '. (<a class="mw-changeslist-watchlist" href="' + mw.util.getUrl( 'Special:Watchlist' ) + '">watchlist</a>) </span>' )
					.append( $dismiss );
		}
	}
	return '';
}
const $watchlyst = $( '<aside>' ).attr( 'id', 'watchlyst' );  // the parent div
api = new mw.Api( {
	ajax: {
		headers: { 'Api-User-Agent': 'Watchlyst/3.1' } },
	parameters: { format: 'json', formatversion: '2', errorformat: 'html' }
} );
function refreshWatchlyst( title = null, timestamp = null ) {
	if ( typeof ( title ) === 'string' ) {
		// strings are immutable, so lets convert which would bump levels correctly
		timestamp = new Date( timestamp );
		timestamp.setSeconds( timestamp.getSeconds() + 1 );
		timestamp = timestamp.toISOString().slice( 0, 19 ) + 'Z'; // API doesn't accept microseconds
		api.postWithToken( 'csrf', { action: 'setnotificationtimestamp', titles: [ title ], timestamp: timestamp } ).done( refreshWatchlyst );
		return;
	}
	$watchlyst.addClass( 'loading' );
	/* Find the top unread item in the watchlist.
        We only need one item, so set the limit to 1 to ease the load on the server. */
	api.get( {
		action: 'query', list: 'watchlist', wllimit: 1, wldir: 'older', wlshow: 'unread',
		wlexcludeuser: mw.config.get( 'wgUserName' ), wlprop: [ 'parsedcomment', 'ids', 'title', 'user', 'loginfo', 'timestamp' ]
	} ).done( ( data ) => $watchlyst.html( getWatchlyst( data ) ).removeClass( 'loading' ) )
		.fail( ( data ) => {
			$watchlyst.removeClass( 'loading' );
			for ( const err in data.errors ) {
				$watchlyst.html( err.module + ': ' + err.html + ' (' + err.code + ') ' );
			}
		} );
}
$( () => {
	if ( mw.config.get( 'wgCanonicalSpecialPageName' ) !== 'Watchlist' ) {
		addCss( ".dismissButton::before { content: '[';  color: #202122; } .dismissButton::after { content: ']';  color: #202122; }" );
		addCss( `.dismissButton {
	background: transparent;
	border: 0; padding: 0;
	cursor: pointer;
				}` );
		addCss( '@media (prefers-reduced-motion: no-preference) { #watchlyst { transition: opacity 0.5s; } }' );
		try { // determine color of link
			addCss( '.dismissButton { color: ' + getComputedStyle( document.querySelector( '.mw-body-content a:link:not([class])' ) ).getPropertyValue( 'color' ) + '; }' );
		} catch ( _ ) {
			addCss( '.dismissButton { color: #36c; }' );
		}
		refreshWatchlyst();
		addCss( '.loading { opacity: 0; }' );
		mw.util.addSubtitle( $watchlyst[ 0 ] );
	}
} );
// </syntaxhighlight>
// [[Category:Wikipedia scripts]]