User:PleaseStand/highlight-comments-dev.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 ) );