Creating a basic JavaScript plugin

8 min read

(For more resources related to this topic, see here.)

Getting started with an empty plugin

To get started, create three files called manifest.xml, MyCompany.WebAccess.Plugin.debug.js, and MyCompany.WebAccess.Plugin.min.js. In the manifest.xml file, place the following XML:

<WebAccess version="12.0"> <plugin name="MyCompany Plugin - Web Access"
vendor="Gordon Beeming" moreinfo="" version="1.0"> <modules> <module namespace="MyCompany.WebAccess.Plugin"
loadAfter="TFS.Agile.TaskBoard.View"/> <module namespace="MyCompany.WebAccess.Plugin"
loadAfter="TFS.Agile.Boards.Controls"/> </modules> </plugin> </WebAccess>

In the preceding code, once the plugin node has the attributes name, vendor, moreinfo, and version, we will be able to easily identify our plugin in the TFS Web Access admin area. Under the modules node, you will see that we have added two child module nodes. This informs TFS that we want to load our MyCompany.WebAccess.Plugin namespace after the TFS.Agile.TaskBoard.View and TFS.Agile.Boards.Controls namespaces, which are namespaces loaded on the task board and portfolio boards. You can get the base of this plugin from the sample code in the MyCompany.WebAccess.Plugin – Base.js file. If you have used the RequireJs module loader, you will notice that this syntax is very familiar.

In the base code, you will see a bit of code like the following:

TfsWebAccessPlugin.prototype.initialize = function () { // place code here to get started alert('MyCompany.WebAccess.Plugin is running'); };

This initialize method is where you start gaining control of what is happening in Web Access. Take all the code in the base code and place it in the debug.js file.

Importing a plugin into TFS Web Access

The first part of importing a plugin into TFS is to make sure that you have placed a minified version of your *.debug.js contents into your *.min.js file. Update the version of your plugin in the manifest.xml file, if required; for now, we will leave it at 1.0.

Zip the three files we created; the name of this ZIP file doesn’t make a difference to the usage of the plugin. Browse to the server’s home page and then click on the Administer Server button in the top-right corner as shown in the following screenshot:

The Administer Server Button

Click on the Extensions tab and then click on Install . In the model window, click on browse to browse for the ZIP file you created with the contents of the plugin and then click on OK . You will now see that the plugin is visible in the extensions screen but is currently not enabled. Click on Enable and then on OK to enable it, as shown in the following screenshot:

Web access extension when disabled

When you navigate to any of the boards, you will see the alert that we placed in the initialize function.

Setting up the debug mode

We have just imported our plugin into TFS, and this was quite a long process. Although it is fine if we upload our plugin into an environment, when we have finished creating our plugin, it becomes very time consuming when we need to make changes to the plugin. You have to go through this whole process to see the changes. So, we will use some tricks that will help us debug our extension.

Enabling the Script Debug Mode

Navigate to the TFS URL with _diagnostics appended at the end, that is, http://gordon-pc:8080/tfs/_diagnostics. On this page, we will click on the Script Debug Mode link, which should currently be disabled. This should also switch Client Trace Point Collector to Enabled , as shown in the following screenshot:

TFS diagnostics settings

This will now make TFS use the debug.js file instead of the min.js file. You will also see more requests for JavaScript files as each file is now streamed separately instead of being bundled together for better load performance. For this reason, it is probably very clear that this should not be enabled on a production environment.

Configuring a Fiddler AutoResponder rule

The next part is to configure Fiddler to automatically respond to any requests for your plugin from the server with your local debug.js file.

You can download Fiddler from We are going to use Fiddler to intercept the request for our plugins’ JavaScript file from TFS and use our local version of the plugin.

The first step would be to start up Fiddler and make sure you can see the request for the MyCompany.WebAccess.Plugin.js file, which should have a URL similar to http://gordon-pc:8080/tfs/_static/tfs/12/_scripts/TFS/debug//tfs/_plugins/1957/MyCompany.WebAccess.Plugin.js.

In Fiddler, switch to the AutoResponder tab and check Enable automatic responses and Unmatched requests passthrough . Now click on Add Rule and in the Rule editor menu, use the regex:http://gordon-pc:8080/tfs/_static/tfs/12/_scripts/TFS/.+/MyCompany.WebAccess.Plugin.js rule; this will put a wildcard on the mode and plugin ID that is being used currently. In the second textbox, write down the full location of the debug.js file for this plugin and then click on Save . Add a second rule in the same pattern, but this time in the second textbox, use header:CachControl=no-cache and click on Save . You should see something similar to the following screenshot in Fiddler:

Fiddler AutoResponder rule added

This will now make Web Access use your local debug.js file for all requests for the plugin in TFS. To try this out, go to the debug.js file, change the alert to we have added debugging , and save the file. Refresh the board, and you will see that without any additional effort, the alert changed.

Adding information to display work items

We will be going through some of the snippets that make a difference and are crucial to our plugin working correctly.

The easiest way to make use of these types of plugins is to change the HTML based on the information available in the HTML; this is useful for small changes, such as displaying the ID of work items on the work item cards on the boards. For this, you would, on initialization of your plugin, use the setInterval function in JavaScript and call the following function every 500 milliseconds:

function TaskBoardFunctions() { //replace IDs for tasks $("#taskboard-table .tbTile").each(function () { var id = $(this).attr("id"); id = id.split('-')[1]; $(this).find(".tbTileContent .witTitle").html
("<span style='font-weight:bold;'>" + id +
"</span> - " + $(this).find(".witTitle").html()); }); //replace IDs for tasks $("#taskboard-table .taskboard-row .taskboard-parent")
.each(function () { var id = $(this).attr("id"); if (id != undefined) { id = id.split('_')[1]; id = id.substring(1); $(this).find(".witTitle")
.html("<span style='font-weight:bold;'>" + id +
"</span> - " + $(this).find(".witTitle").html()); } }); }

This function just looks for all work items on the page using the IDs that are specified in the attributes in the HTML elements to add the IDs to the UI.

A better way to do this would be to make use of the events in the API, and only make modifications to the displayed information when necessary. You would still use something similar to the preceding code for your initial loading to go through the board, and set all the information you would want to display; however, you would reply on the events to do any further updates. So, in this case, we would use the preceding code to scan for all the IDs on the page and then pass that through to a method, such as the following one, which will query the work item store. TFS has a configurable value that tells us the number of results that can be returned per query through the JavaScript API, and for this reason, we query 100 work items at a time; however, you can change this if it’s not applicable to your plugin.

Core.prototype.loadWorkItemsWork = function
(idsToFetch, onComplete, that) { var takeAmount = 100; if (takeAmount >= idsToFetch.length) { takeAmount = idsToFetch.length; } if (takeAmount > 0) {
.beginPageWorkItems(idsToFetch.splice(0,takeAmount), [ "System.Id", "System.State" ], function (payload) { that.loadWorkItemsWork(idsToFetch, onComplete, that); $.each(payload.rows, function (index, row) { onComplete(index, row, that); }); }, function (err) { that.loadWorkItemsWork(idsToFetch, onComplete, that); alert(err); }); } };

As you can see, we are querying the work item store for the ID and the state of each work item on the page. We are then passing this off to an onComplete function that is using jQuery to find the elements by ID. We then alter the displayed information to show the ID, and on the task board to show the state of the requirement.

If you use all the sample code and upload it into TFS, you will see a portfolio board like the one shown in the following screenshot:

IDs on the portfolio board

And on the task board, you will see the following screenshot:

IDs and State on task board

You can see that the tasks have IDs on them, which are the same as the portfolio boards, and the requirements listed on the left have IDs and their current states.


In this article, we covered customizing the TFS dashboard to display information that helps us find out a team’s current status by pinning queries, build status, and recent changes to the source code. We then made some changes to the columns displayed in the portfolio backlog and the quick add panel. We finished off by going through what is required to create a TFS Web Access plugin.

Resources for Article :

Further resources on this subject:


Please enter your comment!
Please enter your name here