Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Anders Hattestad
Feb 20, 2015
  8883
(7 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

Feb 23, 2015 04:40 PM

Nice! I really have to look into all this dojo stuff.

Søren Raarup
Søren Raarup Apr 7, 2015 01:21 PM

Thanks for sharing, Anders :-)

Apr 26, 2017 01:50 PM

Hi. Thank you for a great post. It have bee very helpful in several cases. 

Unfortunatly, the email link-fuction is not woking preoperly after upgrading to Episerver 10.7 when including a similar EditorDescriptorRegistration extension as above. In particular the "malto:"-prefix is no longer added. So for instance, an email link looks like the following.

Email link

So an editor needs to add the "emailto:"-prefix manually i HTML view.

Has anyone else experienced this behavior?

I have been troulbeshooting this and testing several scenarios. Removing the EditorDescriptorRegistration extension will make everything work as it supposed to. But it seems that the path to the email link widget file has been changed. So the following path is not correct and the js-files are not uploaded in the browser as they did before. 

WidgetType = "epi-cms/form/EmailValidationTextBox"

So the question is what is the new correct path? Any ideas? 

Thank you

David Tellander
David Tellander Jul 19, 2017 03:33 PM

I ran into the same problem as Ayman when using this solution, in my case on a 9.7 site.

To fix this I had to add a new property to the HyperLinkModel class:

public Dictionary WidgetSettings { get; set; }


And then on the HyperLinkModel for Email set the addMailTo setting to true, since this is false by default:

WidgetSettings = new Dictionary { {"addMailTo", true} }

/David

Kenia Gonzalez
Kenia Gonzalez Jan 11, 2019 02:54 PM

We're using this solution in our project and it has been working fine in version 7.7 After upgrading to CMS 11.6 the link selection dialog is shown blank. The console shows the following errors:

1: ComponentController::loadComponents widgets.js:2:509770
2: FormContainer::_setupUI undefined widgets.js:2:509770

3: FormContainer::_setupUI undefined

Any ideas? Have you tested the solution in the newest version Anders?

Angel Velazquez
Angel Velazquez Nov 1, 2019 04:42 PM

Hi. We are trying to use this same solution in our project too, but we are having the same or similar results as Kenia mentioned, our dialog box is shown in blank as well.

Kenia, Did you find a way to solved this? or is there any other (if exist...) kind of development to achieve this?

Regards!

James Wilkinson
James Wilkinson Nov 6, 2019 05:17 PM

Did anyone crack this? 

Ynze
Ynze Feb 21, 2022 04:04 AM

For an updated version of the code that works for CMS 11, see this post:

https://ynze.hashnode.dev/extending-the-hyperlink-editor-in-version-11

Aneta Petryla
Aneta Petryla Dec 27, 2022 10:49 AM

Any updates for CMS12? For me, the Url is shown as a normal block on the page instead of Url Selector window, what can be wrong?

Aneta Petryla
Aneta Petryla Dec 27, 2022 10:59 AM

Any updates for CMS12? For me, the Url is shown as a normal block on the page instead of Url Selector window, what can be wrong?

Aneta Petryla
Aneta Petryla Dec 27, 2022 12:49 PM

Any updates for CMS12?  instead of Url Selector window, what can be wrong?

The CustomUrl property is shown as a normal block on the page:

Instead of Link Editor window after clicking "Add link"

What I should implement or change for CMS 12?

RJK Condor
RJK Condor Nov 27, 2023 01:01 PM

Any news for CMS12? Seems to be deserted.

I wanted to add a selector (rel= follow, nofollow) to every link. For the Link property we used Geta's extension DataLink and for the TinyMCE RTE Link I twisted the epi-addon-tinymce/plugins/epi-link/epi-link a bit.

Would be much nicer to define or extend a custom link on one place and use it as block property and in the RTE.

Please login to comment.
Latest blogs
Solving the mystery of high memory usage

Sometimes, my work is easy, the problem could be resolved with one look (when I’m lucky enough to look at where it needs to be looked, just like th...

Quan Mai | Apr 22, 2024 | Syndicated blog

Search & Navigation reporting improvements

From version 16.1.0 there are some updates on the statistics pages: Add pagination to search phrase list Allows choosing a custom date range to get...

Phong | Apr 22, 2024

Optimizely and the never-ending story of the missing globe!

I've worked with Optimizely CMS for 14 years, and there are two things I'm obsessed with: Link validation and the globe that keeps disappearing on...

Tomas Hensrud Gulla | Apr 18, 2024 | Syndicated blog

Visitor Groups Usage Report For Optimizely CMS 12

This add-on offers detailed information on how visitor groups are used and how effective they are within Optimizely CMS. Editors can monitor and...

Adnan Zameer | Apr 18, 2024 | Syndicated blog

Azure AI Language – Abstractive Summarisation in Optimizely CMS

In this article, I show how the abstraction summarisation feature provided by the Azure AI Language platform, can be used within Optimizely CMS to...

Anil Patel | Apr 18, 2024 | Syndicated blog

Fix your Search & Navigation (Find) indexing job, please

Once upon a time, a colleague asked me to look into a customer database with weird spikes in database log usage. (You might start to wonder why I a...

Quan Mai | Apr 17, 2024 | Syndicated blog