Add Telephone Link to the General Link field type in Sitecore

Posted 02/21/2015 by Akshay Sura

I wanted to extend the General Link field to add a new Menu Item to create a Telephone link. A Telephone link is primarily used to render a telephone number so that it helps the mobile user to dial out the phone number.

e.g.: <a title=”Call Customer Service at 1-222-333-4455″ class=”phone” href=”tel:12223334455″>Call Customer Service</a>

In order to achieve this functionality we need to do the following:

1. Go to the Core database, and add a menu item under /sitecore/system/Field types/Link Types/General Link/Menu. Name it Telephone.

2. Set the Display Name field of this newly created Menu Item to Insert Telephone Link

3. Set the Message field to contentlink:telephonelink(id=$Target)

Menu Link

4. Create a class called TelephoneLink to handle the link message. The above entry in the Message Field should match the switch case statement.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Shell.Applications.ContentEditor;
using Sitecore.Text;

namespace YOURNAMESPACE
{
    public class TelephoneLink:Link
    {
        // Handles the message.
        public override void HandleMessage(Sitecore.Web.UI.Sheer.Message message)
        {
            Assert.ArgumentNotNull(message, "message");
            base.HandleMessage(message); //base handles other message requests

            string name = message.Name;
            string str = name;
            if (name != null)
            {
                switch (str)
                {
                    case "contentlink:telephonelink":
                        {
                            var url = new UrlString(UIUtil.GetUri("control:TelephoneLinkForm")); //find control and open url
                            base.Insert(url.ToString());
                            return;
                        }
                    default:
                        {
                            return;
                        }
                }
            }

            if (Value.Length > 0)
            {
                SetModified();
            }
            Value = String.Empty;
        }
    }
}

5. Click on General Link and modify the Control property to content:TelephoneLink

General Link

6. Create a config patch file to register the control source.

<controlSources>
        <source mode="on" namespace="YOURNAMESPACE" assembly="YOURASSEMBLY" prefix="content"/>
</controlSources>

7. Create a new folder called TelephoneLink under /sitecore/shell/Applications/Dialogs 

Explorer

8. Create an xml file called TelephoneLink.xml

<?xml version="1.0" encoding="utf-8" ?>
<control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense">
  <TelephoneLinkForm>
    <FormDialog Icon="Network/32x32/mail.png" Header="Insert a telephone link" 
      Text="Please specify the telephone number address and any additional properties. When done, click OK."
      OKButton="OK">

      <CodeBeside Type="YOURNAMESPACE.TelephoneLinkForm,YOURASSEMBLY"/>

      <a id="telephone"></a>
      
      <GridPanel Class="scFormTable" CellPadding="2" Columns="2" Width="100%">
        <Label For="Text" GridPanel.NoWrap="true"><Literal Text="Link description:"/></Label>
        <Edit ID="Text" Width="100%" GridPanel.Width="100%"/>
        
        <Label For="Url" GridPanel.NoWrap="true"><Literal Text="Telephone Number:"/></Label>
        <Edit ID="Url" Width="100%" />

        <Label For="Class" GridPanel.NoWrap="true"><Literal Text="Style class:" /></Label>
        <Edit ID="Class" Width="100%" />
        
        <Label for="Title" GridPanel.NoWrap="true"><Literal Text="Alternate text:"/></Label>
        <Edit ID="Title" Width="100%" />
      </GridPanel>
    </FormDialog>
  </TelephoneLinkForm>
</control>

9. Create a class called TelephoneLinkForm to act as the code behind for TelephoneLink.xml

using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using Sitecore;
using Sitecore.Diagnostics;
using Sitecore.Shell.Applications.Dialogs;
using Sitecore.Web.UI.HtmlControls;
using Sitecore.Web.UI.Pages;
using Sitecore.Web.UI.Sheer;
using Sitecore.Xml;

namespace YOURNAMESPACE
{
    public class TelephoneLinkForm : LinkForm
    {
        protected Edit Class;
        protected Edit Text;
        protected Edit Title;
        protected Edit Url;

        public TelephoneLinkForm()
        {
        }

        private string GetTelephone()
        {
            string value = this.Url.Value;
            string str = value;
            if (str.Length > 0)
            {
                if (str.IndexOf(":", StringComparison.InvariantCulture) >= 0)
                {
                    str = str.Substring(str.IndexOf(":", StringComparison.InvariantCulture) + 1);
                }
                if (!(new Regex(@"^(1?(-?d{3})-?)?(d{3})(-?d{4})$", RegexOptions.IgnoreCase)).IsMatch(str))
                {
                    return "__Canceled";
                }
            }
            if (value.Length > 0 && value.IndexOf(":", StringComparison.InvariantCulture) < 0)
            {
                value = string.Concat("tel:", value);
            }
            return value;
        }

        protected override void OnLoad(EventArgs e)
        {
            Assert.ArgumentNotNull(e, "e");
            base.OnLoad(e);
            if (Context.ClientPage.IsEvent)
            {
                return;
            }
            string item = base.LinkAttributes["url"];
            if (base.LinkType != "tel")
            {
                item = string.Empty;
            }
            this.Text.Value = base.LinkAttributes["text"];
            this.Url.Value = item.Replace("tel:", "");
            this.Class.Value = base.LinkAttributes["class"];
            this.Title.Value = base.LinkAttributes["title"];
        }

        protected override void OnOK(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull(sender, "sender");
            Assert.ArgumentNotNull(args, "args");
            string tel = this.GetTelephone();
            if (tel == "__Canceled")
            {
                SheerResponse.Alert("The telephone number is invalid.", new string[0]);
                return;
            }
            Packet packet = new Packet("link", new string[0]);
            LinkForm.SetAttribute(packet, "text", this.Text);
            LinkForm.SetAttribute(packet, "linktype", "tel");
            LinkForm.SetAttribute(packet, "url", tel);
            LinkForm.SetAttribute(packet, "anchor", string.Empty);
            LinkForm.SetAttribute(packet, "title", this.Title);
            LinkForm.SetAttribute(packet, "class", this.Class);
            SheerResponse.SetDialogValue(packet.OuterXml);
            base.OnOK(sender, args);
        }
    }
}

10. We need to handle the Rendering of the Telephone Link, so create processor RenderPhoneLink 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Pipelines.RenderField;
using Sitecore.Xml.Xsl;

namespace YOURNAMESPACE
{
    public class RenderPhoneLink
    {
        public void Process(Sitecore.Pipelines.RenderField.RenderFieldArgs args)
        {
            if (args != null && (args.FieldTypeKey == "link" || args.FieldTypeKey == "general link"))
            {
                Sitecore.Data.Fields.LinkField linkField = args.Item.Fields[args.FieldName];
                if (!string.IsNullOrEmpty(linkField.Url) && linkField.LinkType == "tel")
                {
                    args.Parameters["href"] = linkField.Url;
                }
            }
        }

    }
}

11. Add to config patch file to run the RenderPhoneLink processor right before the GetLinkFieldValue processor

<configuration xmlns:x="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <controlSources>
             <source mode="on" namespace="YOURNAMESPACE" assembly="YOURASSEMBLY" prefix="content"/>
        </controlSources>
        <pipelines>
            <renderField>
                <processor patch:before="*[@type='Sitecore.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Kernel']" type="YOURNAMESPACE.RenderPhoneLink, YOURASSEMBLY" />
            </renderField>
        </pipelines>
    </sitecore>
</configuration>

Now all you have to do is to keep using the sc fields such as <sc:Link and the field value will be rendered properly.

Final

If you have any questions or comments please get in touch with me. Thank you.