// ==UserScript==
// @name JIRA Enhanced Navigator
// @version 1.5
// @description Makes the columns in tables resizable and remembers column width, additionally it allows the hiding of the filter box on the left.
// @namespace http://home.comcast.net/~mailerdaemon
// @include */ManageFilters.jspa*
// @include */IssueNavigator.jspa*
// @include */QuickSearch.jspa*
// @include */BulkEditDetailsValidation.jspa*
// @include */BulkEdit1!default.jspa*
// @include */UserVotes!default.jspa*
// @include */UserWatches!default.jspa*
// @include */ViewUserIssueColumns!default.jspa*
// @include */ViewSearchRequestIssueColumns!default.jspa*
// ==/UserScript==
//enable resizing on the Column Order page
const resize_on_ordering = false;
//size of the resize handle
const div_width = 3;
if(!String.prototype.trim) String.prototype.trim = function() {return this.replace(/^\s+|\s+$/g,"");}
function process(array, before, after, between){ return (before?before:"")+no_wrap.join((after?after:"") +(between?between:"")+ (before?before:""))+(after?after:""); }
var domain = document.location.host;
var regex = /[\W\s \n\r]+/g;
var ColumnOrderPage = document.location.pathname.search(/\/View(User|SearchRequest)IssueColumns!default\.jspa/) > -1;
if(ColumnOrderPage)
{
$Z("//table[@id='issuetable']//tr[following-sibling::tr[@class='rowAlternate']]/td/b", function(r,i,p){
c = document.createElement("input")
c.type = "checkbox";
c.title = "Do not wrap long lines."
var temp = r.textContent.replace(regex, "");
c.id = temp?temp:i + "?";
c.checked = GM_getValue(domain+".column."+c.id+".nowrap", false);
insertBefore(c, r);
addEvent(c, "click", function(event){GM_setValue(domain+".column."+this.id+".nowrap", this.checked)});
});
}
if(resize_on_ordering || !ColumnOrderPage)
{
function stop(event){event.stopPropagation();}
function auto(event){
// eb.style.marginLeft=eb.style.marginRight="";
var link = GetParentNodeByTag(event.target, "td");
var name = domain+".column."+link.id+".width";
link.removeAttribute("width");
base.className="resizing";
var w = link.clientWidth-(pad+pad);
link.width=(w<min_width)?min_width:w;
GM_setValue(name, link.width);
base.removeAttribute("class");
// eb.style.marginLeft=eb.style.marginRight="auto";
}
function down(event){
addEvent(document, "mouseup", up);
addEvent(document, "mousemove", movemouse);
dobj = this;
isdrag = true;
x = event.pageX;
w = parseInt(GetParentNodeByTag(dobj, "td").width+".0");
// GM_log(new Array(x,w));
return false;
}
function up(event){
if(isdrag)
{
isdrag=false;
removeEvent(document, "mousemove", movemouse);
removeEvent(document, "mouseup", up);
var link = GetParentNodeByTag(dobj, "td");
var name = domain+".column."+link.id+".width";
// GM_log(name);
GM_setValue( name, link.width);
}
}
function movemouse(event){
if (isdrag)
{
var p = event.pageX;
var k = w + p - x;
GetParentNodeByTag(dobj, "td").width = k<min_width?min_width:k;
// GM_log(new Array(w, p, x, k))
return false;
}
}
function toggle(set){
if(header.style.display == "none" && set != false)
{
header.style.display = "";
GM_setValue(domain+".filter."+header.className+".visible", true)
}
else if(set != true)
{
header.style.display = "none";
GM_setValue(domain+".filter."+header.className+".visible", false)
}
}
var no_wrap = [];
var res = $Y("//table[@id='issuetable']/tbody/tr[position()=1 and not(@class)]/td");
var len = res.snapshotLength;
if(len <= 0) return;
var first = res.snapshotItem(0);
var row = GetParentNodeByTag(first, "tr")
var base = GetParentNodeByTag(row, "table");
var space=parseInt(base.cellSpacing+".0");
var pad = parseInt(base.cellPadding+".0");
var height = (first.height = (base.rows[0].clientHeight - space)) - (pad + pad);// + space + space + pad + pad;
var eb = GetParentNodeByTag(base, "table", base);
//eb.style.backgroundColor="transparent";
eb.removeAttribute("width");
eb.style.marginLeft="20px;"//eb.style.marginRight="auto";
var div_center_offset = (pad /*+ Math.floor(div_width / 2)*/ + space);
var min_width = (ColumnOrderPage?56:div_width - space + 1);
const etype = "div";
for (i = 0; link = res.snapshotItem(i); ++i)
{
link.style.whiteSpace="nowrap";
link.style.minWidth=min_width+"px";
var text = link;
var u = link.getElementsByTagName("span");
if(u && u[0])
{
text = link.removeChild(u[0]);
link.title = text.title;
}
else
{//for BulkEdit1
if(u = getFirstNonTextChild(link))
{
text = document.createElement("span");
text.appendChild(link.removeChild(u));
}
}
var temp = text.textContent.replace(regex, "");
link.id = temp?temp:i + "?";
if(GM_getValue(domain+".column."+link.id+".nowrap", false))
no_wrap.push($X("//table[@id='issuetable']/tbody/tr[preceding-sibling::tr[position()=1 and not(@class)]]/td["+(i+1)+"]").className.replace("nav ",""));
var width = parseInt(GM_getValue(domain+".column."+link.id+".width", "0"));
// GM_log(width);
if(width == 0 || isNaN(width))
width = link.clientWidth - (pad + pad);
if(width < min_width && width >= 0)
width = min_width;
var burn = document.createElement(etype);
var divider = document.createElement(etype);
burn.className="GM_burn";
var t = link.childNodes.length;
while(t > 0)
{
var m = link.removeChild(link.childNodes[--t]);
if(m.nodeName != "#text")
burn.appendChild(m);
}
if(burn.childNodes.length > 0)
{
link.appendChild(divider);
link.appendChild(burn);
}
else
link.appendChild(divider = burn);
if(link != text)
link.appendChild(text);
divider.title="Click and drag to resize this column";
divider.className="GM_divider";
// addEvent(floater, "mouseup", up);
addEvent(divider, "mousedown", down);
addEvent(divider, "click", stop);
addEvent(divider, "dblclick", auto);
link.width=Math.abs(width) + (width>=0?"":"%");
}
GM_addStyle(process(no_wrap, "#issuetable .", " {white-space:nowrap;} "));
//GM_log(no_wrap.join(","));
var tx;
var ty;
var x;
var w;
var dobj;
GM_addStyle(".GM_divider {background-color:black; cursor:col-resize; height:"+height+"px; opacity:0.125; width:"+div_width+"px;} .GM_burn, .GM_divider {float:right; left:"+div_center_offset+"px; position:relative;}")
GM_addStyle("table.resizing {table-layout:auto!important; overflow:auto!important;} table.resizing tbody tr td.colHeaderLink *, table.resizing tbody tr td.colHeaderOver * {display:none;}" );
GM_addStyle("table#issuetable tbody tr td {overflow:hidden!important;} table#issuetable {table-layout:fixed; overflow:hidden; width:0px;}");
GM_addStyle("table#issuetable tbody tr td:hover {overflow:visible!important;} table#issuetable tbody tr td:hover + td {opacity:0.2;} .faded {opacity:0.1!important;}");
GM_addStyle("td.colHeaderOver {color:black;} td.colHeaderOver:hover + td + td {opacity:0.4;}");
var header = $X("//tr[not(boolean(@class))]/td[@class='filterSummaryCell' or @class='filterFormCell' or (not(@class) and div[@class='vcard'])]");
if(header)
{
var div = document.createElement("td");
div.style.background = "#9DBBDA";
div.style.verticalAlign = "middle";
div.style.cursor="pointer";
text = document.createElement("div");
text.style.width = "5px";
div.appendChild(text);
insertAfter(div, header);
addEvent( div, "click", toggle );
if(!header.className)
if(new_name = document.URL.replace(/.*\/([^!]+)\!default\.jspa.*/, "$1"))
header.className = "URL-" + new_name;
toggle(GM_getValue(domain+".filter."+header.className+".visible", true));
div.title="Click to toggle the visiblity of the filters";
}
$Z("//td[contains(@class, 'assignee') and contains(text(), 'Unassigned')]", function(r, i, p){r.className += " faded"}, base);
}
function $X(_xpath, node){return document.evaluate(_xpath, node?node:document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(0);}
function $Y(_xpath, node){return document.evaluate(_xpath, node?node:document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);}
function $Z(_xpath, func, node, payload){
var res = document.evaluate(_xpath, node?node:document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var i, j;
for (i = j = 0; link = res.snapshotItem(i); ++i)
j += func(link, i, payload);
return j;
}
function GetParentNodeByTag(child, tag, bad) {
tag = tag.toUpperCase();
while((child = child.parentNode) && child.tagName != tag);
return child?child:bad;
}
function insertAfter(insert, after){return after.parentNode.insertBefore(insert, after.nextSibling);}
function insertBefore(insert, before){return before.parentNode.insertBefore(insert, before);}
function addEvent( obj, type, fn, capture ) {
if ( obj.attachEvent ) {
obj["e"+type+fn] = fn;
obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
obj.attachEvent( "on"+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, capture?capture:false );
}
function removeEvent( obj, type, fn, capture ) {
if ( obj.detachEvent ) {
obj.detachEvent( "on"+type, obj[type+fn] );
obj[type+fn] = obj["e"+type+fn] = null;
} else
obj.removeEventListener( type, fn, capture?capture:false );
}
function getFirstNonTextChild(obj){
if(obj.firstChild.nodeName != "#text") return obj.firstChild;
return getNextNonTextSibling(obj.firstChild);
}
function getNextNonTextSibling(obj){
while((obj=obj.nextSibling) && (obj.nodeName == "#text"));
return obj;
}