您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds styles and moves things around so that oft-used functions are easier
当前为
// ==UserScript== // @name TFS Helper // @namespace http://jonas.ninja // @version 1.6.1 // @description Adds styles and moves things around so that oft-used functions are easier // @author @_jnblog // @match http://*/tfs/DefaultCollection/*/_backlogs* // @match http://*/tfs/DefaultCollection/*/_versionControl* // @match http://*/tfs/DefaultCollection/*/_workitems* // @require https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js // @grant GM_addStyle // ==/UserScript== /* jshint -W097 */ /* global GM_addStyle */ /* jshint asi: true, multistr: true */ var $ = unsafeWindow.jQuery; var topClass = "makeTfsNotAwful" $('body').addClass(topClass) waitForKeyElements("div.tab-page[rawtitle=Links]", doEverything, false) $(document).on('click', 'input.task-identifier', copyId) .on('dblclick', 'input.task-identifier', copyMessage) function copyId(e) { displayResult(copy(this), $(this).next('span.copy-message'), $(this).parent()) } function copyMessage(e) { var optMessage = makeMessage(this) displayResult(copy(this, optMessage), $(this).next('span.copy-message'), $(this).parent(), true) } function makeMessage(el) { var parent = $(el).closest('.info-text-wrapper') if (parent.length === 0) { console.error("The userscript _TFS Helper_ could not identify this task's name") } return 't' + parent.children('a.caption').text().match(/\d{5,}/)[0] + ' ' + parent.children('.info-text').text().replace(/^dev: /i, "") } function doEverything(linksPane) { if ($(linksPane).data('moved')) { return } showLinksPane(linksPane) stackAllTabs(linksPane) addBlockedButton(linksPane) window.setTimeout(function() { addTaskIdCopyUtilities(linksPane) changeDialogBorderColor(linksPane) }, 250) } function showLinksPane(linksPane) { $(linksPane).data('moved', true) .addClass('linksPanel') .prepend($("<h3>").addClass('linksPanelHeader') .text($(linksPane).attr('rawtitle'))) var link = $('a[rawtitle=Links]') link.closest('td').parent().closest('td').prev().css({'width': '30%' /*, 'padding-right': '12px'*/}) link.closest('td').prepend(linksPane) link.parent().remove() } function changeDialogBorderColor(linksPane) { // depending on the type of this work item, color the border differently var dialog = $(linksPane).closest('.workitem-dialog') var caption = dialog.find('a.caption').text() if (caption.indexOf('Product Backlog Item ') !== -1) { dialog.css('border-color', '#009CCC') // blue } else if (caption.indexOf('Bug ') !== -1) { dialog.css('border-color', '#CC293D') // red } else if (caption.indexOf('Feature ') !== -1) { dialog.css('border-color', '#773B93') // purple } else { // Task dialog.css('border-color', '#E0C252') // yellow } } function stackAllTabs(linksPane) { var column2 = $(linksPane).closest('table.content').parent('.column') if (Math.max(window.innerWidth, document.documentElement.clientWidth) >= 1600) return; column2.add(column2.prev()).css({width: '100%', display: 'block'}) window.dispatchEvent(new Event('resize')); } function addTaskIdCopyUtilities(linksPane) { $('.workitem-info-bar').find('.info-text-wrapper').each(function() { var $header = $(this) if ($header.hasClass('added')) { return } $header.addClass('added') var id = $header.find('a.caption').text().match(/\d+/)[0] var $container = $('<div>').css('display', 'inline-block') $container.append($('<input value="' + id + '"/>').addClass('task-identifier')) $container.append($('<span>').addClass('copy-message')) $header.find('span.info-text').after($container) }); } function addBlockedButton(linksPane) { var blockedInput = linksPane.find('[aria-label=Blocked]'); blockedInput.closest('.control-cell').css({width: 'calc(100% - 60px)', 'min-width': '50px'}) } function copy(elToCopy, optMessage) { var $fakeElem = $('<textarea>'); var succeeded var message = optMessage || elToCopy.value $fakeElem .css({ position: 'absolute', left: '-9999px', top: (window.pageYOffset || document.documentElement.scrollTop) + 'px' }) .attr('readonly', '') .val(message) .appendTo(document.body) select($fakeElem[0]) try { succeeded = document.execCommand('copy') } catch (err) { succeeded = false; } $fakeElem.remove() return succeeded; } function displayResult(success, $messageContainer, $cursorContainer, greenCheck) { if (success) { displayBriefMessage($messageContainer, "Copied" + (greenCheck ? '!' : '')) switchCursorBriefly($cursorContainer, greenCheck) } else { displayBriefMessage($messageContainer, "FAILED") return } } function displayBriefMessage($messageContainer, message) { $messageContainer.show().text(message) window.setTimeout(function() { $messageContainer.fadeOut(500) }, 1250) } function switchCursorBriefly($target, greenCheck) { var $targets = $target.add($target.children()) var cursorClass = 'ijg-check' + (greenCheck ? 'Green' : '') $targets.addClass(cursorClass) window.setTimeout(function() { $targets.removeClass(cursorClass) }, 1750) } var modalStyle = '.workitem-dialog { \ left: 10px !important;\ top: 10px !important;\ width: calc(100% - 20px) !important;\ height: calc(100% - 20px) !important;\ border: 4px solid grey;\ box-shadow: gray 0 0 30px 8px;\ box-sizing: border-box;\ }' var innerModalStyle = '.work-item-view {\ width: calc(100% - 20px);\ margin: 0 10px;\ }' var uiDialogContentStyle = '.ui-dialog-content:not(.modal-dialog) {height: calc(100% - 59px) !important}' var otherStyles = '\ .'+topClass+' table.witform-layout {\ width: calc(100% - 4px);\ }\ .linksPanel {\ display: block !important;\ }\ .linksPanelHeader {\ background-color: #e6e6e6;\ font-size: 11px;\ text-transform: uppercase;\ margin: 0;\ padding: 0 4px 0;\ border: 0;\ white-space: nowrap;\ height: 25px;\ line-height: 2.1;\ }\ input.task-identifier {\ cursor: pointer;\ text-align: center;\ width: 80px;\ margin: 0 16px;\ border: 1px solid #ccc;\ }\ .tbTile {\ width: 100%;\ margin: 0px 0px 3px;\ }\ .subColumn { \ width: calc(50% - 5px); \ margin-right: 5px; \ }\ .linksPanel .grid-cell:not(:only-child) {\ text-indent: 0 !important;\ }\ button.changeset-identifier {\ vertical-align: top;\ line-height: 0;\ padding: 0px 12px;\ height: 22px;\ margin-left: 8px;\ }\ .copy-message {\ font-weight: normal;\ }\ .agile-content-container div.board-tile.ui-draggable:focus {\ box-shadow: 0px 0px 10px 2px; \ }\ .ui-tabs-panel[rawtitle="Description"] .workitemcontrol > div, \ .ui-tabs-panel[rawtitle="Description"] .workitemcontrol > div > .richeditor-container, \ [rawtitle="Steps to Reproduce"] .workitemcontrol > div, \ [rawtitle="Steps to Reproduce"] .workitemcontrol > div > .richeditor-container {\ height: auto !important;\ }\ .ui-tabs-panel .richeditor-editarea {\ position: relative;\ }\ .ui-tabs-panel .richeditor-editarea iframe {\ resize: vertical;\ }\ .witform-layout > tbody > tr.group {\ width: calc(100% - 4px);\ }\ .ijg-check {\ cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA7klEQVRIS7WUaw0CQQwG5xSAA5CAEyyAAywgAQfgAAeAAyQghXyXLGlgHy132+R+NTvT22470DmGznx6CDbAMxU+p2AJ3AAJzsBekrkEFp6KHyVzCHLwj2SqoAYfJVMETThwtAI1Zws8gHvj+XrgF2CXBILrBeigQi9ATcqFG56u6BueoDlJCJ4EL2BVqNZKwnCPIF3X1QxRqT3jnX8n1QNdkZq6qDRWf7mu5LNw+0w9klDluV30j6RYeWnZRSRNeGmSPRIXvLYqahI3vLWLcpIQvCVQ3kpOwKGxo37Snm2qCdanWQiHRxCG2gPdBW+zDC83C5E8rQAAAABJRU5ErkJggg==), auto !important;\ }\ .ijg-checkGreen {\ cursor: url(data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDQxNS41ODIgNDE1LjU4MiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDE1LjU4MiA0MTUuNTgyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTQxMS40Nyw5Ni40MjZsLTQ2LjMxOS00Ni4zMmMtNS40ODItNS40ODItMTQuMzcxLTUuNDgyLTE5Ljg1MywwTDE1Mi4zNDgsMjQzLjA1OGwtODIuMDY2LTgyLjA2NCAgIGMtNS40OC01LjQ4Mi0xNC4zNy01LjQ4Mi0xOS44NTEsMGwtNDYuMzE5LDQ2LjMyYy01LjQ4Miw1LjQ4MS01LjQ4MiwxNC4zNywwLDE5Ljg1MmwxMzguMzExLDEzOC4zMSAgIGMyLjc0MSwyLjc0Miw2LjMzNCw0LjExMiw5LjkyNiw0LjExMmMzLjU5MywwLDcuMTg2LTEuMzcsOS45MjYtNC4xMTJMNDExLjQ3LDExNi4yNzdjMi42MzMtMi42MzIsNC4xMTEtNi4yMDMsNC4xMTEtOS45MjUgICBDNDE1LjU4MiwxMDIuNjI4LDQxNC4xMDMsOTkuMDU5LDQxMS40Nyw5Ni40MjZ6IiBmaWxsPSIjMmQ5ZTFlIi8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg==), auto !important;\ }' GM_addStyle("." + topClass + " " + modalStyle) GM_addStyle("." + topClass + " " + innerModalStyle) GM_addStyle("." + topClass + " " + uiDialogContentStyle) GM_addStyle(otherStyles) function select(element) { // MIT licensed. Author: @zenorocha var selectedText; if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { element.focus(); element.setSelectionRange(0, element.value.length); selectedText = element.value; } else { if (element.hasAttribute('contenteditable')) { element.focus(); } var selection = window.getSelection(); var range = document.createRange(); range.selectNodeContents(element); selection.removeAllRanges(); selection.addRange(range); selectedText = selection.toString(); } return selectedText; } function waitForKeyElements( // CC BY-NC-SA 4.0. Author: BrockA selectorTxt, /* Required: The jQuery selector string that specifies the desired element(s). */ actionFunction, /* Required: The code to run when elements are found. It is passed a jNode to the matched element. */ bWaitOnce, /* Optional: If false, will continue to scan for new elements even after the first match is found. */ iframeSelector /* Optional: If set, identifies the iframe to search. */ ) { var targetNodes, btargetsFound; if (typeof iframeSelector == "undefined") targetNodes = $(selectorTxt); else targetNodes = $(iframeSelector).contents() .find(selectorTxt); if (targetNodes && targetNodes.length > 0) { btargetsFound = true; /*--- Found target node(s). Go through each and act if they are new. */ targetNodes.each(function() { var jThis = $(this); var alreadyFound = jThis.data('alreadyFound') || false; if (!alreadyFound) { //--- Call the payload function. var cancelFound = actionFunction(jThis); if (cancelFound) btargetsFound = false; else jThis.data('alreadyFound', true); } }); } else { btargetsFound = false; } //--- Get the timer-control variable for this selector. var controlObj = waitForKeyElements.controlObj || {}; var controlKey = selectorTxt.replace(/[^\w]/g, "_"); var timeControl = controlObj[controlKey]; //--- Now set or clear the timer as appropriate. if (btargetsFound && bWaitOnce && timeControl) { //--- The only condition where we need to clear the timer. clearInterval(timeControl); delete controlObj[controlKey] } else { //--- Set a timer, if needed. if (!timeControl) { timeControl = setInterval(function() { waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector ); }, 300 ); controlObj[controlKey] = timeControl; } } waitForKeyElements.controlObj = controlObj; }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址