Add new tab in General Link field type of Sitecore

Task: Do you want to extend general link field type to include one more tab like create tab for tracking google events?

You can achieve this by following below steps:

1: Create a new item (Menu item) in core database under (/sitecore/system/Field types/Link Types/General Link/Menu).

2: Create a Class Library project.

3: Create a config file and write namespace, assembly and prefix.

<configuration xmlns:x="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <controlSources>
            <source mode="on" namespace="GoogleAnalyticsLib" assembly="GoogleAnalyticsLib" prefix="content"/>
        </controlSources>
    </sitecore>
</configuration>

4: Update the Control field of General Link Item by prefix (from config file) colon (:) class name which are responsible for handle message.

content:GoogleEvent

5: Write the content in message field of newly created item(Menu Item).

Ex. contentlink:GoogleEvent(id=$Target).

6: Create a class for open new tab in form window and inherit by Link class (Sitecore.Kernel).

Code -

public class GoogleEvent : Link
{
    // Sets the value.
    public void SetValue(string value)
    {
        Value = value;
    }
    // Gets the value.
    public string GetValue()
    {
        return Value;
    }
    // Handles the message.
    public override void HandleMessage(Sitecore.Web.UI.Sheer.Message message)
    {
        base.HandleMessage(message);
        if (message["id"] != ID || String.IsNullOrEmpty(message.Name))
        {
            return;
        }
        // in future can be some other message handling
        switch (message.Name)
        {
            case "contentlink:GoogleEvent":
            var url = new UrlString(UIUtil.GetUri("control:GoogleTrackinglink"));
            base.Insert(url.ToString());
            return;
        }
        if (Value.Length > 0)
        {
            SetModified();
        }
        Value = String.Empty;
    }
}
Note:The Message name should be same as new menu itemmessagefield content.

7: Create a XAML file with required fields.

Code of XAML for google event tracking:

<GoogleTrackinglink>
    <FormDialog
    Icon="Network/32x32/link.png"
    Header="Google Link"
    Text="Select the item that you want to create a link to and specify the appropriate properties."
    OKButton="OK" />
        <script type="text/javascript" language="javascript">
            function isNumberKey(evt)
            {
                var charCode = (evt.which) ? evt.which : event.keyCode;
                if (charCode > 40)
                if(charCode &lt; 48 || charCode > 57)
                {
                       return false;
                }
                return true;
            }
        </script>
        <CodeBeside Type="GoogleAnalyticsLib.GoogleEventLinkForm,GoogleAnalyticsLib"/>
        <DataContext ID="GoogleLinkDataContext"/>
        <GridPanel Columns="2" Width="100%" Height="100%" CellPadding="4" Style="table-layout:fixed">
            <Scrollbox Width="256" Height="100%" Background="transparent" Border="none" GridPanel.VAlign="top" GridPanel.Width="256">
                    <GridPanel CellPadding="2" Columns="2">
                            <Literal Text="Category:" GridPanel.NoWrap="true"/>
                            <Edit ID="Category"/>
                            <Literal Text="Action:" GridPanel.NoWrap="true"/>
                            <Edit ID="Action"/>
                            <Literal Text="Label:" GridPanel.NoWrap="true"/>
                            <Edit ID="Label1"/>
                            <Literal Text="Value:" GridPanel.NoWrap="true" />
                            <Edit ID="Value1" onkeypress="javascript:return isNumberKey(event);"/>
                            <Literal Text="Non-interaction:" GridPanel.NoWrap="true"/>
                            <Checkbox ID="Noninteraction"/>
                    </GridPanel>
            </Scrollbox>
        </GridPanel>
    </FormDialog>
</GoogleTrackinglink>
8: Create a class to handle the Dialog form fields
Code -
namespace GoogleAnalyticsLib
{
    public class GoogleEventLinkForm:DialogForm
    {
        protected Edit Category;
        protected Edit Action;
        protected Edit Label1;
        protected DataContext GoogleLinkDataContext;
        protected Edit Value1;
        protected Checkbox NonInteraction;
        Database masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
        protected override void OnLoad(EventArgs e)
        {
            Assert.ArgumentNotNull(e, "e");
            base.OnLoad(e);
            if (Sitecore.Context.ClientPage.IsEvent)
            {
                return;
            }
            this.GoogleLinkDataContext.GetFromQueryString();
            string xml = StringUtil.GetString(new string[] { WebUtil.GetQueryString("va"), "" });
            string queryString = WebUtil.GetQueryString("ro");
            XmlDocument document = XmlUtil.LoadXml(xml);
            System.Xml.XmlNode node = document.SelectSingleNode("/link");
            string attribute = XmlUtil.GetAttribute("category", node);
            string str4 = XmlUtil.GetAttribute("action", node);
            string str5 = XmlUtil.GetAttribute("label1", node);
            string str6 = string.Empty;
            string str7 = XmlUtil.GetAttribute("value1", node);
            string str8 = XmlUtil.GetAttribute("noninteraction", node);
            this.Category.Value = attribute;
            this.Action.Value = str4;
            this.Label1.Value = str5;
            this.Value1.Value = str7;
            this.NonInteraction.Value = str8;
            string str11 = XmlUtil.GetAttribute("id", node);
        }
        // Handler for ok button click
        protected override void OnOK(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull(sender, "sender");
            Assert.ArgumentNotNull(args, "args");
            this.GoogleLinkDataContext.GetFromQueryString();
            string xml = StringUtil.GetString(new string[] {WebUtil.GetQueryString("va"), ""});
            string queryString = WebUtil.GetQueryString("ro");
            XmlDocument document = XmlUtil.LoadXml(xml);
            System.Xml.XmlNode node = document.SelectSingleNode("/link");
            Packet packet = new Packet(document);
            SetAttribute(packet, "category", this.Category.Value);
            SetAttribute(packet, "action", this.Action.Value);
            SetAttribute(packet, "label1", this.Label1.Value);
            SetAttribute(packet, "value1", this.Value1.Value);
            SetAttribute(packet, "noninteraction", this.NonInteraction.Value);
            if (!string.IsNullOrEmpty(this.Category.Value) && !string.IsNullOrEmpty(this.Action.Value))
            {
                // get event tracking code from global header
                Item itm = ProServ.Globals.Common.GetGlobalHeader(masterDb);
                string onClickValues = itm.Fields["Google Event Tracking Code"].Value;
                string strParameters = null;
                strParameters = this.Category.Value;
                strParameters = strParameters + "," + this.Action.Value;
                if (!string.IsNullOrEmpty(this.Label1.Value))
                {
                    strParameters = strParameters + "," + this.Label1.Value;
                }
                if (!string.IsNullOrEmpty(this.Value1.Value))
                {
                    strParameters = strParameters + "," + this.Value1.Value;
                }
                if (!string.IsNullOrEmpty(this.NonInteraction.Value) && this.NonInteraction.Value=="1")
                {
                    strParameters = strParameters + "," + "true";
                }
                onClickValues = onClickValues.Replace("$EventDetail$", strParameters);
                string finalValues = onClickValues;
                SetAttribute(packet, "onclick", finalValues);
            }
            Sitecore.Context.ClientPage.ClientResponse.SetDialogValue(packet.OuterXml);
            base.OnOK(sender, args);
        }
        // set attribute name and value of controls
        private static void SetAttribute(Packet packet, string name, string value)
        {
            Assert.ArgumentNotNull(packet, "packet");
            Assert.ArgumentNotNullOrEmpty(name, "name");
            Assert.ArgumentNotNull(value, "value");
            packet.SetAttribute(name, value);
        }
    }
}