World is now on Opti ID! Learn more

Anders Hattestad
Feb 20, 2015
  3466
(0 votes)

Extending the HyperLink with custom field

I needed to extend the popup with a new field where the editors could add a phone number. In EPiServer 7.5 this can be done by extending the EditorDescriptorRegistration
    [EditorDescriptorRegistration(TargetType = typeof (string), UIHint = "HyperLink",
        EditorDescriptorBehavior = EditorDescriptorBehavior.OverrideDefault)]
    public class LinkEditorDescriptor : EditorDescriptor
    {
        private readonly LocalizationService _localizationService;

        public LinkEditorDescriptor() : this(LocalizationService.Current)
        {
        }

        public LinkEditorDescriptor(LocalizationService localizationService)
        {
            _localizationService = localizationService;
        }

        public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes)
        {
            base.ModifyMetadata(metadata, attributes);
            IEnumerable<IContentRepositoryDescriptor> allInstances =
                ServiceLocator.Current.GetAllInstances<IContentRepositoryDescriptor>();
            List<HyperLinkModel> list = (
                from r in allInstances
                orderby r.SortOrder
                where r.LinkableTypes != null && r.LinkableTypes.Count() > 0
                select new HyperLinkModel
                {
                    Name = r.CustomSelectTitle ?? r.Name,
                    Roots = r.Roots,
                    WidgetType = "epi-cms/widget/ContentSelector",
                    LinkableTypes = r.LinkableTypes,
                    SearchArea = r.SearchArea
                }).ToList<HyperLinkModel>();
            list.InsertRange(list.Count, new[]
            {
                new HyperLinkModel
                {
                    Name = "Email",
                    Title = _localizationService.GetString("/episerver/cms/widget/editlink/emailtooltip"),
                    DisplayName = _localizationService.GetString("/episerver/cms/widget/editlink/email"),
                    WidgetType = "epi-cms/form/EmailValidationTextBox"
                },
                new HyperLinkModel
                {
                    Name = "ExternalLink",
                    Title = _localizationService.GetString("/episerver/cms/widget/editlink/externallinktooltip"),
                    DisplayName = _localizationService.GetString("/episerver/cms/widget/editlink/externallink"),
                    WidgetType = "epi-cms/form/UrlValidationTextBox"
                },
                new HyperLinkModel
                {
                    Name = "FreeTextLink",
                    Title = "Other links",
                    DisplayName = "Other",
                    WidgetType = "alloy/TextBoxMustHaveValue"
                },
                new HyperLinkModel
                {
                    Name = "Anchor",
                    Title = _localizationService.GetString("/episerver/cms/widget/editlink/anchortooltip"),
                    DisplayName = _localizationService.GetString("/episerver/cms/widget/editlink/anchor"),
                    WidgetType = "epi-cms/form/AnchorSelectionEditor",
                    Invisible = true
                }
            });
            metadata.EditorConfiguration["providers"] = list;
            metadata.GroupName = "Href";
            metadata.GroupSettings = new GroupSettings
            {
                Name = metadata.GroupName,
                ClientLayoutClass = "epi.shell.layout.LayoutContainer",
                DisplayUI = true
            };
            metadata.ClientEditingClass = "epi-cms/widget/HyperLinkSelector";
        }
    }

    internal class HyperLinkModel
    {
        public string Name { get; set; }
        public string DisplayName { get; set; }
        public string Title { get; set; }
        public IEnumerable<ContentReference> Roots { get; set; }
        public string WidgetType { get; set; }
        public IEnumerable<Type> LinkableTypes { get; set; }
        public bool Invisible { get; set; }
        public string SearchArea { get; set; }
    }
}

I needed to create my own HyperLinkModel since its internal

Then I needed to create a dojo class like this

define("alloy/TextBoxMustHaveValue", [
    "dojo/_base/declare",
    "dojo/_base/lang",
    "dojox/validate/web",
    "dijit/form/ValidationTextBox",
    // Resources
    "epi/i18n!epi/cms/nls/episerver.cms.form.emailvalidation"
], function (
    declare,
    lang,
    validator,
    ValidationTextBox,
// Resources
    resources
    ) {

    return declare([ValidationTextBox], {
        // summary:
        //    Represents the email input textbox.
        // tags:
        //    internal

        validator: function (value, constraints) {
            // summary:
            //                               Validate the text input with email address validation.
            // tags:
            //                               overrided

            return (!this.required && this._isEmpty(value)) || (!this._isEmpty(value));
          
        },

        invalidMessage: resources.invalidmessage

    });
});

And then register the path in modules.config

<dojo>
    <!-- Add a mapping from alloy to ~/ClientResources/Scripts to the dojo loader configuration -->
    <paths>
      <add name="alloy" path="Scripts" />
    </paths>
  </dojo>

clip_image002

And then the result

Feb 20, 2015

Comments

Please login to comment.
Latest blogs
Make Global Assets Site- and Language-Aware at Indexing Time

I had a support case the other day with a question around search on global assets on a multisite. This is the result of that investigation. This co...

dada | Jun 26, 2025

The remote server returned an error: (400) Bad Request – when configuring Azure Storage for an older Optimizely CMS site

How to fix a strange issue that occurred when I moved editor-uploaded files for some old Optimizely CMS 11 solutions to Azure Storage.

Tomas Hensrud Gulla | Jun 26, 2025 |

Enable Opal AI for your Optimizely products

Learn how to enable Opal AI, and meet your infinite workforce.

Tomas Hensrud Gulla | Jun 25, 2025 |

Deploying to Optimizely Frontend Hosting: A Practical Guide

Optimizely Frontend Hosting is a cloud-based solution for deploying headless frontend applications - currently supporting only Next.js projects. It...

Szymon Uryga | Jun 25, 2025

World on Opti ID

We're excited to announce that world.optimizely.com is now integrated with Opti ID! What does this mean for you? New Users:  You can now log in wit...

Patrick Lam | Jun 22, 2025

Avoid Scandinavian Letters in File Names in Optimizely CMS

Discover how Scandinavian letters in file names can break media in Optimizely CMS—and learn a simple code fix to automatically sanitize uploads for...

Henning Sjørbotten | Jun 19, 2025 |