User:PleaseStand/highlight-comments.js

/** * Highlights specific users' posts to discussion pages using a CSS class. * * Originally written by PleaseStand in 2010, updated for MediaWiki 1.17 in 2011 * Rewrite completed in 2012 * * Released to the public domain; see http://en.wikipedia.org/wiki/Template:PD-self */

( function ( mw, $ ) {

"use strict";

// Default settings var settings = { highlighterFunction: function ( hc ) { // Default highlighter function hc.addColorForUsers( '#ff7', [mw.config.get( 'wgUserName' )] ); hc.wrapComments; hc.addMenuItem; }	};

/**	 * Messages displayed by this script (in English). * Any translations (see below) replace these at runtime. */	var msg = { highlightText: 'Highlight', highlightTooltip: 'Enable highlighting of your own comments on this page', unhighlightText: 'Unhighlight', unhighlightTooltip: 'Disable highlighting of your own comments on this page' };

/**	 * Translations for messages displayed by this script. * To have your translations added, please contact this script's maintainer. */	var translations = { };

// Load translations. $.extend( msg, translations[document.documentElement.lang] );

// Initialize other enclosed variables. var linkMap = Object.create( null ), classNumber = 0, pageRE = null, commentsAreHighlighted = false;

/**	 * Build pageRE, a regexp for the use of findPageNameFromHref. */	function buildPageRE { var articlePathParts = mw.config.get( 'wgArticlePath' ).split( '$1' ); var articlePathStartRE = mw.util.escapeRegExp( articlePathParts[0] ); var articlePathEndRE = mw.util.escapeRegExp( articlePathParts[1] ); var indexPathRE = mw.util.escapeRegExp( mw.util.wikiScript( 'index' ) );

return new RegExp(			'^(?:' + articlePathStartRE + '([^?#]+)' + articlePathEndRE + '|' + indexPathRE + '\\?(?:[^&#]*&)*title=([^&#]+))'		); }

/**	 * Find a linked page's name (with underscores, not spaces) given a relative URL. * This assumes the page is linked using a normal, intra-wiki link. */	function findPageNameFromHref( href ) { var m = pageRE.exec( href ); return m ? decodeURIComponent(			( m[1] || m[2] ).replace( /\+/g, '%20' )		).replace( / /g, '_' ) : null; }

/**	 * Give comments linking to any given page a specific CSS class. * @see unwrapComments */	function wrapComments { wrapElementComments( $( '.mw-highlight-comments' ) ); commentsAreHighlighted = true; addMenuItem( true ); }

/**	 * Mechanics of wrapComments, excluding the flag and menu item updates. *	 * Essentially, we need to find the comment's container and wrap (except where unnecessary) * everything inside except replies to that comment. We can filter the replies out in that * they are inside other element types that have the effect of indenting the text. *	 * @param content The DOM element(s) containing the content. This may be a jQuery object. */	function wrapElementComments( content ) { // Elements containing comments or indented text (replies to those comments) var commentTags = 'dd, li, p', indentTags = 'dl, ol, ul';

$( 'a', content ).each( function {			var pageName = findPageNameFromHref( this.getAttribute( 'href' ) );			// linkMap is from linked page names to CSS class names.			if ( pageName && pageName in linkMap ) {				var className = linkMap[pageName];				$( this ).closest( commentTags ).contents.each( function  { if ( this.nodeType === 1 ) { var $elem = $( this ); if ( !$elem.is( indentTags ) && !$elem.hasClass( className ) ) { $elem .addClass( className ) .attr( 'data-mw-highlighted-comment-class', className ); }					} else { $( this ).wrap( $( ' ', { 'class': className, 'data-mw-highlighted-comment-wrapper': '' } ) );					}				} );			}		} );	}

/**	 * Undo the actions performed by wrapComments. */	function unwrapComments { // Remove added wrappers $( '[data-mw-highlighted-comment-wrapper]' ).replaceWith( function {			return this.childNodes;		} );

// Remove added classes $( '[data-mw-highlighted-comment-class]' ).removeClass( function {			var klass = $( this ).attr( 'data-mw-highlighted-comment-class' );			$( this ).removeAttr( 'data-mw-highlighted-comment-class' );			return klass;		} );

commentsAreHighlighted = false; addMenuItem( true ); }

/**	 * Add a group of users whose comments should be given the same CSS class. * @param className The CSS class name to use * @param users An array of usernames */	function addClassForUsers( className, users ) { var ns = mw.config.get( 'wgFormattedNamespaces' ); for ( var i = 0; i < users.length; ++i ) { var userName = users[i].replace( / /g, '_' ); var userPage = ns[2] + ':' + userName, userTalkPage = ns[3] + ':' + userName; linkMap[userPage] = className; linkMap[userTalkPage] = className; }	}

/**	 * Add a group of users whose comments should be highlighted in the same color. * @param color The CSS background-color to use * @param users An array of usernames * @return The resulting CSSStyleSheet object */	function addColorForUsers( color, users ) { var className = 'highlighted-comment-' + classNumber++; addClassForUsers( className, users ); return mw.util.addCSS( '.' + className + ' { background-color: ' + color + '; }' ); }

/**	 * Adds or updates a "Highlight" or "Unhighlight" option in the content action menu. * @param updateOnly Do nothing if the menu item does not already exist? */	function addMenuItem( updateOnly ) { var text, tooltip, $oldItem = $( '#ca-highlightcomments' );

if ( updateOnly && !$oldItem.length ) { return; }

if ( commentsAreHighlighted ) { text = msg.unhighlightText; tooltip = msg.unhighlightTooltip; } else { text = msg.highlightText; tooltip = msg.highlightTooltip; }

var link = mw.util.addPortletLink(			'p-cactions', '#', text, 'ca-highlightcomments', tooltip, null, $oldItem[0]		); $oldItem.remove;

$( link ).click(function {			if ( commentsAreHighlighted ) {				unwrapComments;			} else {				wrapComments;			}		}); }

// Members exposed to custom highlighter functions var hc = { addClassForUsers: addClassForUsers, addColorForUsers: addColorForUsers, addMenuItem: addMenuItem, wrapComments: wrapComments };

mw.loader.using( [ 'mediawiki.util' ], function {		// Cache pageRE for performance.		pageRE = buildPageRE;

// Run either the user's highlighter function or the default one. $( function {			$.extend( settings, window.highlightCommentsSettings );			settings.highlighterFunction( hc );		} );

// Now that all settings have been processed, get the elements // in which comments should be highlighted. Of course, actually // highlight them if that is desired. mw.hook( 'wikipage.content' ).add( function ( $content ) {			$content.addClass( 'mw-highlight-comments' );			if ( commentsAreHighlighted ) {				wrapElementComments( $content );			}		} ); } );

}( mediaWiki, jQuery ) );