JIRA Enhanced Navigator

Makes the columns in tables resizable and remembers column width, additionally it allows the hiding of the filter box on the left.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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;
}