Adding Content Files to Work Item Custom Control Extension Package
In the previous 2 posts, we talked about how you can develop and deploy work item custom controls using the new architecture of TF Web Access 2012. In the previous posts we developed work item custom controls using HTML and JavaScript. However, in a real world scenario, developers will often need to use content files like images or css for a custom control. This post is about how to include these files in a WICC extension package.
We will continue to use VoteButton as the sample custom control and add an icon to the button.
First thing you need to do is have a reference to the base URL of the module. This URL is used to construct a reference to the content files included in the extension package. Defining the base URL module scoped is better because it will be available to all the controls inside that module:
TFS.module("ACME.VoteButton", ["TFS.WorkItemTracking.Controls", "TFS.WorkItemTracking", "TFS.Core"], function () {
var WITOM = TFS.WorkItemTracking,
WITCONTROLS = TFS.WorkItemTracking.Controls,
delegate = TFS.Core.delegate,
moduleBaseUrl = TFS.getModuleBase("ACME.VoteButton");
// Constructor for VoteButton
function VoteButton(container, options, workItemType) {
this.baseConstructor.call(this, container, options, workItemType);
}
Using this base URL, it is really easy to construct the URL to access any content file using the name specified in the extension package.
_init: function () {
this._base();
// Create vote button
this._control = $("<button type='submit' />").appendTo(this._container).bind("click", delegate(this, this._onClick));
// Add vote icon
$("<img />").attr("src", moduleBaseUrl + "vote.png").attr("align", "absMiddle").prependTo(this._control);
// Add button text
this._buttonText = $("<span />").text("Vote").appendTo(this._control);
}
The following changes also need to be made in order to have the control work correctly.
// Update the control data
// Framework calls this method when the control needs to update itself, such as when:
// - work item form is bound to a specific work item
// - underlying field value has changed due to rules or another control logic
invalidate: function (flushing) {
// Get the vote count from the underlying field
var voteCount = this._getField().getValue() || 0;
// Display the number of votes if any
if (voteCount > 1) {
this._buttonText.text(voteCount + " votes");
} else if (voteCount == 1) {
this._buttonText.text(voteCount + " vote");
} else {
this._buttonText.text("Vote");
}
},
// Clear the control data
// Framework calls this method when the control needs to reset its state to "blank", such as when:
// - work item form is unbound from a specific work item
clear: function () {
this._buttonText.text("Vote");
}
Then the extension package is recreated by including the content file as well.
After uploading the package to TFS, VoteButton should be seen with an icon.
Beside images, you can have your own css file inside the package. With the following JavaScript trick, it is possible to get css file working for the document.
$("<link />").attr("href", moduleBaseUrl + "my.css")
.attr("type", "text/css")
.attr("rel", "stylesheet")
.appendTo($("head").first());
Let us know if you have any questions or feedback.
Comments
Anonymous
July 24, 2012
Great work so far! Do you have any plans to post a blog about creating new tabs in Web Access?Anonymous
July 25, 2012
@Andrew, Adding a hub through extensions is not supported at the moment unfortunately. However, we are considering to support it as we get requests about it. We'll let you know in this blog about the availability. ThanksAnonymous
September 03, 2012
Hi Serkan, Can you pls mention how add radio button/ checkbox to a work item. -ThanksAnonymous
September 10, 2012
@InnocentBoy, For checkbox, you don't need a custom control. If you set the type of your field to "Boolean", you can use FieldControl to have your field displayed as a checkbox, like following: <Control FieldName="My.Boolean.Field" Type="FieldControl" Label="Checkbox Label" /> For radio buttons, you can take this sample code as the base and in the initialize, instead of creating button, creating the radio button will do the trick for you. Let me know if you more questions.Anonymous
October 03, 2012
Hi Serkan, Excellent info on Web Access customization. Is there any official documentation about the Web Access client side object model? What exactly can we customize, what namespaces are there, etc? I would really like to learn more about customizing this because the new Web Access is very promising! Thanks, JeffryAnonymous
January 03, 2013
hi i want to put an custom control of textbox type how do i add it and how can i get the text value from the controlAnonymous
April 17, 2013
Hi, Serkan! Great work! Will create a button with which you can load the file into TFS through a web interface (TFS Web Access)? Thanks!Anonymous
April 29, 2013
Hey! Thanks for the information, seeing as there is like no documentation this is quite helpful. Can I ask how you would go about adding a custom .js file?Anonymous
May 13, 2013
@Tom, would you like to add a 3rd party library along with your custom control implementation?Anonymous
May 13, 2013
@Oleg Markitanov, I'm not sure I understood your question correctly. Do you want to have a custom control with an upload button included? You should be able to do it easily by adding input type of file to the provided container using jQuery. However, I'd like to know more about it to see how it's different that ordinary AttachmentsControl.Anonymous
February 05, 2014
For those who are interested (and ar eworking with a text field that contains "Yes" or "No", I have created this custom "AzCheckBox" TFS.module("AzCheckBox", [ "TFS.WorkItemTracking.Controls", "TFS.WorkItemTracking", "TFS.Core" ], function () { // module content var WITOM = TFS.WorkItemTracking, WITCONTROLS = TFS.WorkItemTracking.Controls, delegate = TFS.Core.delegate; // Constructor for AzCheckBox function AzCheckBox(container, options, workItemType) { this.baseConstructor.call(this, container, options, workItemType); } AzCheckBox.inherit(WITCONTROLS.WorkItemControl, { _control:null, _init: function () { this._base(); this._control = $("<input type='checkbox' >").appendTo(this._container).bind("change", delegate(this, this.onChanged)); }, invalidate: function (flushing) { if (this._readOnly) { this._control.attr("disabled", "disabled"); } else { this._control.removeAttr("disabled"); } this._control.attr("checked", this._getField().getValue()); }, getValue: function () { return this._control.attr("checked") ? true : false; }, clear: function () { this._control.attr("checked", false); }, onChanged : function (e) { this._workItemControl._getField().setValue(this.getValue()); }, }); WITCONTROLS.registerWorkItemControl("AzCheckBox", AzCheckBox); return {AzCheckBox: AzCheckBox}; }); <WebAccess version="12.0"> <plugin name="AzCheckBox" vendor="" moreinfo="" version="1.0.0" > <modules > <module namespace="AzCheckBox" loadAfter="TFS.WorkItemTracking.Controls"/> </modules> </plugin> </WebAccess>