// ==UserScript==
// @name C€ Portfolio Overview - Jira 5 Rapid Board - Dev
// @namespace de.controlexpert.jira.rapidboard
// @description Customization for cards displayed on the Jira RapidBoard forked from "IS24 Portfolio Overview - Jira 5 Rapid Board" http://userscripts.org/scripts/show/172077
// @include https://jira.controlexpert.com/secure/RapidBoard.jspa?rapidView=*
// @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @version v2 _ce
// @grant none
// ==/UserScript==
/* ===============
* Version History
* ===============
* v2 _ce 2014-03-28 - Start in BirdView with colourized cards
* v1.01 _ce 2014-03-28 - Description of the card contain now key and summary in title attribute (tooltip)
*/
/* -------------
* Configuration
* -------------
*/
const BACKGROUND_COLOR = "rgba(22, 75, 106, 1)";
const MENU_BACKGROUND_COLOR = "rgba(26, 90, 127, 1)";
const MENU_HOVER_COLOR = "rgb(31,108,150)";
const ISSUE_HOVER_COLOR = "rgba(153, 173, 194, 1)";
const ISSUE_HEIGHT = 60;
const ISSUE_GRABBER_HEIGHT = 77;
const ISSUE_WIDTH = 88;
const ISSUE_FONT_SIZE = "8pt";
const SWIMLANE_HEADER_SIZE = "18pt";
const COLUMN_HEADER_SIZE = "18pt";
const FOREGROUND_COLOR = "white";
const YELLOW_MARKER_COLOR = "rgba(247,223,86,1)";
const RED_MARKER_COLOR = "rgba(181,75,50,1)";
/* Number of the development column */
var columnId = 2;
/* tickets that are more days than this in development are marked red */
const DAYS_RED = 180;
/* tickets that are more days than this in development are marked red */
const DAYS_YELLOW = 28;
var inProgressBarMode = false;
var inColorizeServiceLineMode = false;
/* The JQuery selector to a dom node to which custom buttons for zoom and other features are added */
//var NODE_TO_ADD_CUSTOM_BUTTONS = "div#ghx-controls-work dl:last-child";
var NODE_TO_ADD_CUSTOM_BUTTONS = "div#ghx-controls-work dl";
var ghxPool = $("#ghx-pool");
var allGhxIssues = ghxPool.find("div.ghx-issue");
var allFirstGhxIssues = ghxPool.find("div.ghx-issue:first-child");
/* Fix for Greasemonkey 1.0 bug, see http://www.greasespot.net/2012/08/greasemonkey-10-jquery-broken-with.html */
$ = this.$ = this.jQuery = jQuery.noConflict(true);
function addCss(css) {
var newCss = document.createElement("style");
newCss.type = "text/css";
newCss.innerHTML = css;
$("head")[0].appendChild(newCss);
}
function overwriteStaticCss() {
log("overwriteStaticCss...");
/* =================
* Overall Background
* ==================*/
/* make backgrounds blue */
addCss("#content { background: " + BACKGROUND_COLOR + " }");
addCss("#ghx-pool { background: " + BACKGROUND_COLOR + " }");
addCss("#ghx-column-headers { background: " + BACKGROUND_COLOR + " }");
addCss("#ghx-column-header-group.ghx-fixed {background: none}");
/* =================
* Header
* ==================*/
addCss(".aui-theme-default #header #logo a img { padding:0 }");
addCss("#ghx-header { padding-left:0 }");
addCss("#ghx-work { border:none }");
addCss("#ghx-operations {padding:0}");
addCss(".aui-theme-default #header .global { background: " + BACKGROUND_COLOR + " }");
addCss(".aui-theme-default #content { margin:0; padding-top:0; padding-bottom:0; padding-left:16px }");
addCss(".aui-theme-default #header .global .secondary>ul>li { background: " + BACKGROUND_COLOR + "}");
addCss("h2#ghx-board-name { color: " + FOREGROUND_COLOR + ";font-weight:bold }");
// Hide some stuff that is not helping us here
addCss(".alertHeader { display:none }");
addCss("#ghx-modes { display:none }");
addCss(".SpartezAC-print { display:none }");
addCss(".ghx-compact-toggle { display:none }");
addCss(".local { display:none }");
addCss("#js-swimlane-header-stalker {display:none !important}");
addCss(".ghx-feedback {display:none}");
/* =================
* Buttons
* ==================*/
addCss(".aui-theme-default a, .aui-theme-default a:link, .aui-theme-default a:visited { color:white;background: " + MENU_BACKGROUND_COLOR + ";border:none;margin:0;padding-top:5px;padding-bottom:5px;padding-left:5px;padding-right:5px }");
addCss(".aui-theme-default a:hover { color:white;background: " + MENU_HOVER_COLOR + ";margin:2px;border:none;margin:0;text-decoration:none }");
addCss(".aui-theme-default .aui-list .aui-list-item-link { color:white }");
addCss(".ghx-controls-filters dd a.ghx-active {color:white;border:none;background: " + MENU_HOVER_COLOR + "}");
addCss("#ghx-release {display:none}");
addCss(".aui-theme-default #header #logo a { background: " + BACKGROUND_COLOR + "}");
/* ==========
* Issue Cards
* ===========*/
addCss(".ghx-issue:hover {background:" + ISSUE_HOVER_COLOR + "}");
/* add a shadow to cards */
addCss(".ghx-issue { box-shadow: none; background:white}");
/* make issues floating and round corners*/
addCss(".ghx-issue { float: left; cursor: pointer; border-radius: 0 0 10px 0;margin:2px}");
addCss(".ghx-grabber { background:white; display:none}");
addCss(".ghx-issue .ghx-grabber:after { background:none;}");
/* Hide epic symbol */
addCss(".ghx-issue { padding-left: 12px; padding-top: 8px }");
addCss(".ghx-issue-fields .ghx-type { display: none }");
addCss(".ghx-issue:first-child { border: none }");
/* hide priority symbol */
addCss(".ghx-priority { display:none }");
/* make text on the "cards" bigger so that more is visible */
addCss(".ghx-summary { font-size: " + ISSUE_FONT_SIZE + " }");
addCss(".ghx-issue-fields { padding-right: 0px !important; }");
addCss(".ghx-issue-fields .ghx-key {font-size: " + ISSUE_FONT_SIZE + "; height: 13px; line-height: 0.98em; overflow:visible; vertical-align:baseline}");
addCss(".ghx-issue-fields .ghx-key a { background: none;color: " + BACKGROUND_COLOR + "; word-wrap: break-word;display:block}");
addCss(".ghx-issue-fields .ghx-summary span, .ghx-issue-subtask .ghx-issue-fields .ghx-summary span { height: 5em; line-height: 0.98em }");
/* Care for tasks */
addCss(".ghx-issue-subtask .ghx-issue-fields .ghx-summary { font-size: " + ISSUE_FONT_SIZE + " }");
addCss(".ghx-issue-subtask .ghx-issue-fields .ghx-key, .ghx-issue-subtask .ghx-issue-fields .ghx-summary {font-size: " + ISSUE_FONT_SIZE + "; height: 13px; line-height: 0.98em }");
addCss(".ghx-issue-subtask .ghx-issue-fields .ghx-key, .ghx-issue-subtask .ghx-issue-fields .ghx-summary { color: " + BACKGROUND_COLOR + "; word-wrap: break-word;display:block}");
addCss(".ghx-issue-subtask .ghx-issue-fields .ghx-key a { white-space: normal}");
/* make avatars invisible */
addCss(".ghx-issue .ghx-avatar img { height: 35px; width: 35px; opacity: 0.5; display:none }");
/* remove lines through resolved issue keys */
addCss(".ghx-issue.ghx-done .ghx-key a { text-decoration: none; }");
addCss(".ghx-issue.ghx-done .ghx-key a:hover { text-decoration: underline; }");
/* hide days spent dots */
addCss(".ghx-days { display:none}");
/* ====================
* Columns and Swimlanes
* =====================*/
addCss("#ghx-pool {padding:0}");
/* make column and swim lane headers bigger and modify colors */
addCss(".ghx-swimlane-header { font-size: " + SWIMLANE_HEADER_SIZE + "; background: " + BACKGROUND_COLOR + "; border:none;color: " + FOREGROUND_COLOR + "; font-size: " + COLUMN_HEADER_SIZE + ";");
addCss(".ghx-column-headers h2 { font-weight:normal;margin:0;line-height:1.2}");
addCss("#ghx-column-header-group {left: 28px !important}");
// add a separator border
addCss(".ghx-info:after {background-color: #fff;content: '';height: 1px;position: absolute;width: 95%;top: 25px;}");
addCss(".ghx-swimlane-header:after {display: none}");
addCss(".ghx-column-headers .ghx-column, .ghx-columns .ghx-column { background: " + BACKGROUND_COLOR + "; color: " + FOREGROUND_COLOR + " ;border:none; padding:0}");
addCss(".ghx-column-headers .ghx-column h2 { color: " + FOREGROUND_COLOR + "; font-size: " + COLUMN_HEADER_SIZE + "; float: left }");
addCss("li.ghx-column { padding-left: 15px;}");
/* number of issues */
addCss(".ghx-column-headers .ghx-qty { color: " + FOREGROUND_COLOR + ";background:" + BACKGROUND_COLOR + ";border:none;font-weight:normal; margin-left:5px}");
addCss(".ghx-columns {padding-left:13px}");
addCss(".ghx-qty { color: " + FOREGROUND_COLOR + ";background:" + BACKGROUND_COLOR + ";border:none;position:relative;margin:0; font-size:" + COLUMN_HEADER_SIZE + ";font-weight:normal }");
addCss(".ghx-description {color: " + FOREGROUND_COLOR + ";margin-right:5px}");
log("overwriteStaticCss done");
}
function markLateTickets() {
log("markLateTickets...");
if(inColorizeServiceLineMode) {
log("markinColorizeServiceLineMode aborting...");
return;
}
$(".ghx-grabber").css("display","none");
$("li.ghx-column[data-column-id=" + columnId + "] div.ghx-issue").each(function () {
var days = $().find(".ghx-days").attr("title");
days = Number(days.substring(0, days.indexOf(" ")));
if (days > DAYS_RED) {
$(this).find(".ghx-grabber").css("background", RED_MARKER_COLOR).css("display", "block");
} else if (days > DAYS_YELLOW) {
$(this).find(".ghx-grabber").css("background", YELLOW_MARKER_COLOR).css("display", "block");
}
});
log("markLateTickets done");
}
function adjustColumnSizes() {
log("adjustColumnSizes...");
$(".ghx-column-headers li:first-child").css("width", "25%");
$(".ghx-column-headers li:last-child").css("width", "25%");
$(".ghx-columns li:first-child").each(function () {
$(this).css("width", "25%");
});
$(".ghx-columns li:last-child").each(function () {
$(this).css("width", "25%");
});
log("adjustColumnSizes done");
}
function enterProgressBarView() {
log("entering progress bar view...")
$(".ghx-summary").css("display", "none");
$(".ghx-issue-fields .ghx-key").css("font-size", "6pt");
$("div.ghx-issue").css("padding-left","0").css("padding-top","0").css("margin","1px").width(ISSUE_WIDTH / 2.8).height(ISSUE_HEIGHT / 5.0);
$("div.ghx-issue:first-child").css("padding-left","0").css("padding-top","0").css("margin","1px").width(ISSUE_WIDTH / 2.8).height(ISSUE_HEIGHT / 5.0);
$(".ghx-issue .ghx-grabber").height(ISSUE_GRABBER_HEIGHT / 3.3);
$(".ghx-issue:first-child .ghx-grabber").height(ISSUE_GRABBER_HEIGHT / 3.4);
$(".ghx-swimlane-header .ghx-heading").css("margin","0px");
$(".ghx-column-headers .ghx-column h2").css("font-size", "8pt");
$(".ghx-swimlane-header").css("font-size", "8pt");
$(".ghx-qty").css("font-size", "8pt");
$(".ghx-columns .ghx-column").css("padding-bottom", 0);
$(".ghx-issue .ghx-avatar img").height("10px").width("10px");
$(".ghx-description").css("display","none");
log("progress bar view entered");
}
function leaveProgressBarView() {
log("leaving progress bar view");
$(".ghx-summary").css("display", "inline");
$(".ghx-issue-fields .ghx-key").css("font-size", "10pt");
log("1");
$("div.ghx-issue").css("padding-left","12px").css("padding-top","8px").css("margin","2px");
$("div.ghx-issue").width(ISSUE_WIDTH);
$("div.ghx-issue").height(ISSUE_HEIGHT);
log("2");
$("div.ghx-issue:first-child").css("padding-left","12px").css("padding-top","8px").css("margin","2px").width(ISSUE_WIDTH).height(ISSUE_HEIGHT);
log("3");
$(".ghx-issue .ghx-grabber").height(ISSUE_GRABBER_HEIGHT);
$(".ghx-issue:first-child .ghx-grabber").height(ISSUE_GRABBER_HEIGHT);
$(".ghx-swimlane-header .ghx-heading").css("margin-top","10px");
log("4");
$(".ghx-column-headers .ghx-column h2").css("font-size", SWIMLANE_HEADER_SIZE);
$(".ghx-swimlane-header").css("font-size", COLUMN_HEADER_SIZE);
$(".ghx-qty").css("font-size", COLUMN_HEADER_SIZE);
$(".ghx-columns .ghx-column").css("padding-bottom", 32);
$(".ghx-issue .ghx-avatar img").height("35px").width("35px");
$(".ghx-description").css("display","inline-block");
log("progress bar view left");
}
function refreshProgressBarView() {
log("refreshing progress bar view...");
if (inProgressBarMode) {
enterProgressBarView();
} else {
leaveProgressBarView();
}
log("progress bar view refreshed");
}
function enterColorizeAgeMode() {
log("enterColorizeAgeMode...");
markLateTickets();
log("enterColorizeAgeMode done");
}
function enterColorizeServiceLineMode() {
log("enterColorizeServiceLineMode...");
$(".ghx-grabber").css("display","block");
GH.EpicView.updateEpicColor
log("enterColorizeServiceLineMode done");
}
function toggleIssueColorization() {
if (inColorizeServiceLineMode) {
inColorizeServiceLineMode = !inColorizeServiceLineMode;
enterColorizeAgeMode();
} else {
inColorizeServiceLineMode = !inColorizeServiceLineMode;
enterColorizeServiceLineMode();
}
if ("Colorize ServiceLines" == $("#colorText").text()) {
$("#colorText").text("Colorize age");
} else {
$("#colorText").text("Colorize ServiceLines");
}
}
function toggleProgressBarView() {
if (inProgressBarMode) {
leaveProgressBarView();
} else {
enterProgressBarView();
}
inProgressBarMode = !inProgressBarMode;
if ("Zoom out" == $("#zoomText").text()) {
$("#zoomText").text("Zoom in");
} else {
$("#zoomText").text("Zoom out");
}
}
function convertFilterButtonsIntoPullDown() {
log("convertFilterButtonsIntoPullDown...");
// Wait for the list of quick filters to be available
$("div#ghx-controls-work dl").onAvailable(function() {
$("div#ghx-controls-work dl:first-child > dt").css("display","none");
// Add a new list to the above div and put one item inside which will be the button to hover the pull down menu
$("<dl><dt id='slFilterButton' style='font-weight:normal;line-height:1.4;background:" + MENU_BACKGROUND_COLOR + ";background-position: 8% 50%;background-repeat: no-repeat;background-image: url(\"/rest/api/1.0/dropdowns?color=%23ffffff&bgcolor=%23114070\");padding-top:4px;padding-left:24px;padding-right:5px;padding-bottom:5px;color:white;font-size:10pt;cursor: pointer'>Filter by...</dt></dl>").appendTo($("div#ghx-controls-work"));
// Now move all ServiceLine, Department or other orga filters into the newly created list
$("dd:not(:contains('SL '))dd:not(:contains('DEP '))dd:not(:contains('Supporting Teams'))dd:not(:contains('External'))dd:not(:contains('PMI'))dd:not(:contains('Project Management'))").detach().appendTo($("div#ghx-controls-work dl:last-child"));
// Reformat the original list that now contains all ServiceLine filters, etc. so that it is hidden and lies under the "Filter by..." button.
$("div#ghx-controls-work dl:first-child").css('list-style', 'none').css('position', 'absolute').css('left', '15px').css('top', '25px').css('float', 'left').css('display', 'none').css('z-index', '99').css('width', '180px').css('margin', '0').css('padding', '0').css('background', MENU_BACKGROUND_COLOR);
$("div#ghx-controls-work dl:first-child > dd").css('width', '180px').css('margin', '0').css('padding', '0').css('border', 'none').css('clear', 'both');
// Reformat the new list with the moved itemss
$("div#ghx-controls-work dl:last-child > dd").css("font-size","10pt").css("padding-top","4px").css("padding-right","5px").css("padding-bottom","5px").css("background",MENU_BACKGROUND_COLOR).css("color","white");
// Slide down the original list under the button and make it visible
$("#slFilterButton").on("mouseenter", function () {
$(this).css('background', MENU_HOVER_COLOR).css('background-position', '8% 50%').css('background-repeat', 'no-repeat').css('background-image', 'url(\"/rest/api/1.0/dropdowns?color=%23ffffff&bgcolor=%23114070\")');
$("div#ghx-controls-work dl:first-child").slideDown('fast');
})
// Slide up again and hide the list
$("div#ghx-controls-work dl:first-child").hover(function () {
}, function () {
$("#slFilterButton").css('background', MENU_BACKGROUND_COLOR).css('background-position', '8% 50%').css('background-repeat', 'no-repeat').css('background-image', 'url(\"/rest/api/1.0/dropdowns?color=%23ffffff&bgcolor=%23114070\")');
$("div#ghx-controls-work dl:first-child").slideUp('slow');
})
});
log("convertFilterButtonsIntoPullDown done");
}
function addColorizeButtonToButtonBar() {
$(NODE_TO_ADD_CUSTOM_BUTTONS).onAvailable(function () {
$("<dd id='colorizeButton' style='padding-top:6px;background:" + MENU_BACKGROUND_COLOR + ";color:white;font-size:10pt;cursor: pointer;padding-left:5px;padding-top:4px;padding-bottom:5px;padding-right:5px'><span id='colorText'>Colorize ServiceLines</span></dd>").appendTo(NODE_TO_ADD_CUSTOM_BUTTONS);
$("#colorizeButton").on("click",function () {
toggleIssueColorization()
}).on("mouseenter",function () {
$(this).css('background', MENU_HOVER_COLOR);
}).on("mouseleave", function () {
$(this).css('background', MENU_BACKGROUND_COLOR);
})
}
)
}
function addZoomButtonToButtonBar() {
$(NODE_TO_ADD_CUSTOM_BUTTONS).onAvailable(function () {
$("<dd id='zoomButton' style='padding-top:6px;background:" + MENU_BACKGROUND_COLOR + ";color:white;font-size:10pt;cursor: pointer;padding-left:5px;padding-top:4px;padding-bottom:5px;padding-right:5px'><span id='zoomText'>Zoom out</span></dd>").appendTo(NODE_TO_ADD_CUSTOM_BUTTONS);
$("#zoomButton").on("click",function () {
toggleProgressBarView()
}).on("mouseenter",function () {
$(this).css('background', MENU_HOVER_COLOR);
}).on("mouseleave", function () {
$(this).css('background', MENU_BACKGROUND_COLOR);
})
}
)
}
function addShowAssigneeButtonToButtonBar() {
$(NODE_TO_ADD_CUSTOM_BUTTONS).onAvailable(function () {
$("<dd id='showAsigneeButton' style='padding-top:6px;background:" + MENU_BACKGROUND_COLOR + ";color:white;font-size:10pt;cursor: pointer;padding-left:5px;padding-top:4px;padding-bottom:5px;padding-right:5px'><span id='showAsigneesText'>Show asignees</span></dd>").appendTo(NODE_TO_ADD_CUSTOM_BUTTONS);
$("#showAsigneeButton").on("click",function () {
showAsignees();
}).on("mouseenter",function () {
$(this).css('background', MENU_HOVER_COLOR);
}).on("mouseleave", function () {
$(this).css('background', MENU_BACKGROUND_COLOR);
})
}
)
}
function showAsignees() {
if($(".ghx-issue .ghx-avatar img").css("display") == "block") {
$("#showAsigneesText").text("Show asignees");
$(".ghx-issue .ghx-avatar img").css("display","none");
} else {
$("#showAsigneesText").text("Hide asignees");
$(".ghx-issue .ghx-avatar img").css("display","block");
}
}
function identifyInProgressColumnId() {
$("#ghx-column-headers li.ghx-column h2").onAvailable(function() {
$("#ghx-column-headers li.ghx-column h2").each(function() {
var columnName = $(this).text().trim();
if (columnName == "In Progress") {
columnId = $(this).parent().attr("data-id");
}
})
});
}
function joinTitlesOfKeyAndSummery(){
log("joinTitlesOfKeyAndSummery...");
var res = $(".ghx-issue-fields").not(" .ghx-key-link [title*='\n']").each(function() {
var keyEl = $(this).children(".ghx-key").children(".ghx-key-link").not("[title*='\n']");
if (keyEl.length>0){
var summaryEl = $(this).children(".ghx-summary");
var newTitleText = keyEl.attr("title").trim() + "\n" + summaryEl.attr("title").trim()
var newline = "
";
keyEl.attr("title", newTitleText);
summaryEl.attr("title", newTitleText);
}
});
log(res.length + " elements affected");
log("joinTitlesOfKeyAndSummery done");
}
function beautifyBoard() {
log("beautifyBoard...");
overwriteStaticCss();
overwriteCssAfterRefresh();
addZoomButtonToButtonBar();
addShowAssigneeButtonToButtonBar();
addColorizeButtonToButtonBar();
convertFilterButtonsIntoPullDown();
log("beautifyBoard done");
}
function overwriteCssAfterRefresh() {
log("overwriteCssAfterRefresh...");
$(".ghx-issue").onAvailable(function () {
log("available");
identifyInProgressColumnId();
adjustColumnSizes();
markLateTickets();
refreshProgressBarView();
joinTitlesOfKeyAndSummery();
});
$("#zoomText").onAvailable(function(){
//$("#zoomText").click();
log("zoomed: "+$("#zoomText"));
});
log("overwriteCssAfterRefresh done");
}
var DOMTimeout = null;
$(document).ready(function () {
console.log(new Date().toLocaleTimeString() + " document is ready");
beautifyBoard();
$("#ghx-work").on("DOMNodeInserted", function (event) {
if('A' != event.target.nodeName) {
return;
}
if(DOMTimeout) {
clearTimeout(DOMTimeout);
}
//DOMTimeout = setTimeout(function() {
//
// overwriteCssAfterRefresh();
//
//}, 150);
});
});
function log(text) {
console.log(new Date().toLocaleTimeString() + " " + text);
}
/* Adds functionality to jQuery to wait for an element to be available;
* this is useful for the rapid board because most of the page is loaded
* after document ready by Ajax */
$.fn.onAvailable = function (fn) {
var sel = this.selector;
var timer;
if (this.length > 0) {
fn.call(this);
}
else {
timer = setInterval(function () {
if ($(sel).length > 0) {
fn.call($(sel));
clearInterval(timer);
}
}, 1000);
}
};