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.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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;
}