kavi089 / ColoredLabels

// ==UserScript==
// @name        ColoredLabels
// @namespace   LucasRollan
// @description Use story labels to create a visual representation of stories status in Jira
// @include     https://jira.swacorp.com/plugins/servlet/gadgets/ifr?*
// @include     https://jira.swab2bqa.com/plugins/servlet/gadgets/ifr?*
// @include     https://jira.swacorp.com/secure/Dashboard.jspa*
// @include     https://jira.swab2bqa.com/secure/Dashboard.jspa*
// @grant       none
// @version     3.00
// ==/UserScript==


/*** CONFIG VARIABLES ***/
var labelsConfig = {						// Script defaults	|  Jira defaults
	showEmptyLabels: false,					//	false			|	false
    showLabelsColumn: false,				//	false			|	false
    collapseHighLevelPointEstimate: true,	//	true			|	false
    collapseFinalPointEstimate: true,		//	true			|	false
    showTotalPointsEstimate: true			//	true			|	false
};


/*** Script Definition ***/

labelsConfig.getTextDefinition = function() {
	var text = 'var labelsConfig = {\n';
	for (var property in this) {
		if (typeof labelsConfig[property] != 'function') {
			text += '    '+ property +': '+ labelsConfig[property] + ',\n';
		}
	}
	text = text.substring(0, text.length - 2);
	text += '\n}';
	
	return text;
};

var ColoredLabels = {};

ColoredLabels.injectCode = function(code) {
    this.inject('script', 'text/javascript', code);
};
ColoredLabels.injectCSS = function(code) {
    this.inject('style', 'text/css', code);
};
ColoredLabels.inject = function(tag, type, code) {
	var head = document.getElementsByTagName('head')[0];
	var obj = document.createElement(tag);
	obj.type = type;
	obj.innerHTML = code;
	head.appendChild(obj);
};

ColoredLabels.getFunctionListCode = function(nameList) {
	var code = '';
	for (var i in nameList) {
		code += this.getFunctionCode(nameList[i]);
	}
	return code;
};
ColoredLabels.getFunctionCode = function(name) {
	var code = 'var '+ name +' = ' + this[name].toString() + ';\n';
	return code;
};

ColoredLabels.createLabels = function() {
	var $ = jQuery;
	
    var people = {	
      "AA": "Alfonsina Altamira",
        
      "AR": "Ahsan Raza",
      "CF": "Cheryl Fisk",
      "DA": "Daniel Aguilera",
      "DJ": "Daniela Jacquelin",
      "MT": "Marcos Torres",
      "RB": "Romina Bianucci",
      
      "AE": "Alexis Escudero",
      "CU": "Cristian Urbano",
      "ES": "Emiliano Santi",
      "EE": "Emmanuel Elmoni",
      "EZ": "Ezequiel Von Ziegler",
      "FG": "Flavia Gramajo",
      "GZ": "Gonzalo Zunino",
      "HS": "Hernan Seghetti",
      "JB": "Javier Baccarelli",
      "JD": "Julio Danni",  
      "KP": "Kevin Prox",
      "MER": "Mariano Remedi",   
      "MAR": "Martin Rodriguez",     
      "NS": "Nicolas Siandro",
      "QC": "Qaiser Chaudhry",
      "ZW": "Zane Wu",     

      "AB": "Agustina Bosso",
      "AF": "Ariel Fonseca",
      "GB": "Gisele Brizuela",
      "IF": "Ivana Fenoglio",
      "LR": "Lucas Rodriguez",
      "SG": "Silvia Garcia"

	};
	
	var CSS = '.ColoredLabel {\n';
        CSS += '    height: 20px;\n';
        CSS += '    border: solid 1px gray;\n';
        CSS += '    border-radius: 5px;\n';
        CSS += '    font-weight: bold;\n';
        CSS += '    text-align: center;\n';
        CSS += '    line-height: 20px;\n';
        CSS += '    font-family: arial,sans-serif;\n';
        CSS += '    font-size: 12px;\n';
        CSS += '    cursor: default;\n';
        CSS += '}\n';
        CSS += '.RED {\n';
        CSS += '    background-color: red;\n';
        CSS += '    color: white;\n';
        CSS += '}\n';
        CSS += '.YELLOW {\n';
        CSS += '    background-color: yellow;\n';
        CSS += '    color: black;\n';
        CSS += '}\n';
        CSS += '.GREEN {\n';
        CSS += '    background-color: green;\n';
        CSS += '    color: white;\n';
        CSS += '}\n';
	injectCSS(CSS);
    
	var divTemplate = '<div title="{TITLE}" class="ColoredLabel {COLOR}">{CONTENT}</div>';
	var rowTemplate = '<td class="nav">{DIV}</td>';
	    
    addColoredLabelsTableHeaders();
    function addColoredLabelsTableHeaders() {
        $('tr.rowHeader>th[rel^="labels"]').after('<th>BA</th><th>DEV</th><th>QC</th>');
    };

    if (!labelsConfig.showLabelsColumn) {
        hideLabelsColumn();
    }
    function hideLabelsColumn() {
        $('tr.rowHeader>th[rel^="labels"]').hide();
    };
    
    if (labelsConfig.collapseHighLevelPointEstimate) {
        replaceHlpeText();
   	}
    function replaceHlpeText() {
        $('span[title="Sort By High Level Points Estimate"]').text('HLPE');
    };
    
    if (labelsConfig.collapseFinalPointEstimate) {
        replaceFpeText();
    }
    function replaceFpeText() {
        $('span[title="Sort By Final Points Estimate"]').text('FPE');
    };
    
    if (labelsConfig.showTotalPointsEstimate) {
        if (fpeExists()) {
        	showTotalFpe();
        } else {
        	showTotalHlpe();
        }
    }
    function totalPointsInit() {
    	$('.aui-group.count-pagination').css('margin-top','-28px');
    }
    function fpeExists () {
    	return $('th span').index($('[title="Sort By Final Points Estimate"]')) != -1;
    }
     function showTotalFpe() {
        var index = getFpeIndex();
        var count = sumEstimates(index);
        
        var numCells = countColumns();
        if (count) {
        	totalPointsInit();
        	$('table').append(createTotalsRow(numCells, count, index));
        }
    };
    function getFpeIndex () {
         return $('th span').index($('[title="Sort By Final Points Estimate"]'));
    };
    function showTotalHlpe() {
        var index = getHlpeIndex();
        var count = sumEstimates(index);
        
        var numCells = countColumns();
        if (count) {
        	totalPointsInit();
        	$('table').append(createTotalsRow(numCells, count, index));
        }
    };
    function getHlpeIndex () {
         return $('th span').index($('[title="Sort By High Level Points Estimate"]'));
    };
    function sumEstimates (pos) {
        var count = 0;
        $('tr').each(function(){count += $(this).children('td:eq('+ pos +')').text()*1;});
        return count;
    };
	function countColumns () {
		return $('tr:eq(1)>td').length;
	};
    function createTotalsRow (numCells, total, position) {
        var row = $('<tr></tr>');
        for (var i = 0; i < numCells; i++) {
            var cell = $('<td></td>');
            if (i == position) {
                cell.html('<b>'+total+'</b>');
            } else if (i == position-1) {
                cell.css('text-align','right');
                cell.html('<b>Total</b>');
            }
            row.append(cell);
        }
        return row;
    };
	
	$('td.labels').each(
		function(){
			var availableLabels = ['BA','DEV','QC']; // < label categories
			var labels = {};
			for (var key in availableLabels) {
				labels[availableLabels[key]] = {color:'', content:'', title:''}; // < label properties
			}
            //e.g. availableLabels['BA'].color
            //To add new labels this is the place ^
			
			$(this).children('div').children('ul').children('li').each( //each label
				function() {
					var inner = $(this).html();
					for (var type in labels) { //parse each type
                        var regex = new RegExp(type + '\\.(\\w+)(?:\\.(\\w{1,3}))?'); //{TYPE}.{COLOR}.{INITIALS} -> e.g. DEV.GREEN.LR // [2 or 3 initials]
						var results = inner.match(regex);
						if (results) { //matches
							labels[type].color = results[1];
							labels[type].content = results[2] || '';
							labels[type].title = people[labels[type].content] || '';
                            
							$(this).hide();
						}
					}
				}
			);
			
			var insert = '';
			for (var type in labels) {
				var currentDiv = divTemplate;
				if (labelsConfig.showEmptyLabels || (labels[type].color !== '')) {
					for (var property in labels[type]) {
						currentDiv = currentDiv.replace('{'+ property.toUpperCase() +'}', labels[type][property]);
					}
				} else {
					currentDiv = '';
				}
				insert += rowTemplate.replace('{DIV}', currentDiv);
			}
			$(this).after(insert);
            if (!labelsConfig.showLabelsColumn) {
                $(this).hide();
            }
		}
	);
    
    requestSetHeight($('table#issuetable').parent().height());
};

ColoredLabels.requestSetHeight = function(size) {
    parent.setIframeHeight(size, location.href);
}


ColoredLabels.setIframeHeight = function(size, url) {
    var $ = jQuery;
    
	var iframeId = $('iframe[src="'+ url +'"]').height(size).attr('id');
    var containerId = iframeId.replace('gadget','rep');
    $('#'+ containerId).height(size + 32);
    refreshPositions();
    
    function refreshPositions() {
        $('li[id^="rep-"].gadget').each(function(){
        	var boxId = $(this).attr('id').replace('rep','gadget') + '-renderbox';
            $('#'+ boxId).css('top', $(this).position().top);
        });
    }
    
    //gadget-30424
    //rep-30424
    //gadget-30424-renderbox
}

ColoredLabels.waitForPageLoad = function() {
    $ = jQuery;
	var table = document.getElementById('issuetable');
	if (table) {
        if (!$('#issuetable').hasClass('ColoredLabelsStarted')) {
            $('#issuetable').addClass('ColoredLabelsStarted');
			createLabels();
        }
	}
};

ColoredLabels.setTimer = function() {
	timeInterval = setInterval(waitForPageLoad, 1 * 1000);
};

if (location.pathname == '/secure/Dashboard.jspa') {
	code = ColoredLabels.getFunctionCode('setIframeHeight');
} else {
	code = ColoredLabels.getFunctionListCode(['injectCSS','inject', 'createLabels', 'requestSetHeight', 'waitForPageLoad', 'setTimer'])+ labelsConfig.getTextDefinition() +';\n setTimer();';
}

ColoredLabels.injectCode(code);