+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / Add "ImageField" as custom field for Blogs, make it return Guid

Add "ImageField" as custom field for Blogs, make it return Guid

11 posts, 0 answered
  1. Stephen
    Stephen avatar
    4 posts
    Registered:
    27 Apr 2012
    04 Jun 2012
    Link to this post
    OK, so looking for some help from the smart community on this one:

    I need to associate an image with a Blog Post.  I've added a custom field of name "Image", type "Short Text" and set the custom template as "Telerik.Sitefinity.Web.UI.Fields.ImageField" as per the following post:
    http://www.sitefinity.com/devnet/forums/sitefinity-4-x/developing-with-sitefinity/wordpress-to-sitefinity-blog-conversion.aspx

    This is working really well, I like the way it works in the backend.

    To render this on the Blog Post page, my Widget Template has added the line:
    <img src='<%# Eval("Image")%>' />
    This also works.

    HOWEVER, because this "Telerik.Sitefinity.Web.UI.Fields.ImageField" is returning the image selected and storing the URL as a string in my custom field, I can't access the images alt-text.

    I have two options as I see it:
    1) Using API, lookup the image by Url/Filepath or similar.  Although titles of image should be unique (I think?) this seems hackish and I'm nervous that if someone changes the image URL/Title my link between that image and the blog post might break

    2) Much better would be to store the selected images Guid.  Then in code-behind I can lookup the image by Guid and access MediaUrl & AlternateText and be happy.

    Can anyone offer any insight into how to achieve this please?  This is doing my head in and holding up progress on our latest site.
  2. MB
    MB avatar
    302 posts
    Registered:
    09 Jan 2005
    04 Jun 2012
    Link to this post
    ImageField (selector) can provide the selected GUID to the client.
    Accessed from:  .get_selectedImageItem().Id
  3. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    04 Jun 2012
    Link to this post
    Legend, this is exactly what I need, and seems like it will work really well.  I've actually used similar code in my Javascript for a Custom Widget with Designer.

    I just don't understand how to set a custom Javascript file/call in the backend "Content -> Blogs" area to achieve this functionality, whereby the ImageField will return Guid, instead of String.  It was easy enough when working with Widgets.

    MB/Sitefinity - do you have any insight into this?

  4. Stephen2
    Stephen2 avatar
    94 posts
    Registered:
    05 Feb 2012
    04 Jun 2012
    Link to this post
    In fact, thinking quickly about this - am I potentially creating a Control that is a complete copy of the ImageField but with a different line or 2 of javascript?

    Or a Control that inherits ImageField, but references a different javascript file?

    I wish the Image Selector with Guid AND String was built in as a field type all throughout Sitefinity, as just about everything needs to select images... News/Blogs/Widgets/Module Builder etc...

  5. Michael
    Michael avatar
    67 posts
    Registered:
    16 Mar 2012
    29 Jun 2012
    Link to this post
    I will second that this needs to be built in. It is already a built in option for items built using the Module Builder.
  6. Michael
    Michael avatar
    67 posts
    Registered:
    16 Mar 2012
    02 Jul 2012
    Link to this post
    By the way, I'm tagging along as I have to do the exact same thing here.

    It appears that if we could add a custom field of type GUID instead of ShortText that the ImageField would work as we want out of the box, but I'm at a loss for how you do that.

    The Javascript at least points to three supported modes: ContentLink, String, or GUID. If we can trigger that GUID storage, that's exactly what we are both looking for.

    I tried to use the "SimpleImageField" sample but the thing is an absolute mess. I was not able to get it to work anywhere, and trying to reimplement left me completely lost. 

    The other option perhaps would be to inherit from the ImageField type and attempt to make it ALWAYS return a GUID instead of a URL. I'm unsure how you would do that exactly. Perhaps override the GetScriptReferences() method, and provide your own Javascript file / override the prototype that ImageField provides by default? It looks like, just picking through the Javascript a bit, that there is a switch statement that chooses which of these values to return based on _dataFieldType. If you could just override the get_value function and just return the GUID part of that, would that do the trick?

    Edit: And I just tried to do that, but I am not able to use my field because I'm getting a Null reference exception in Telerik.Sitefinity.Web.UI.Fields.ImageField.GetScriptDescriptors() line 137. All I did was inherit, override GetScriptReferences(), and supplied my own Javascript file that overrides the Telerik.Sitefinity.Web.UI.Fields.ImageField.prototype.get_value function.

    Unfortunately I do not know the pipeline here well enough to understand what that means.
  7. Michael
    Michael avatar
    67 posts
    Registered:
    16 Mar 2012
    12 Jul 2012
    Link to this post
    Ok, I have a functional module that does this for Image, Document and Videos. It was based off of the SimpleImageField example, but I cleaned it up quite a bit (With a lot of help from the Telerik support staff... thanks again guys). I'd be willing to share if anyone wants to take it and run with it, but I have no intention of maintaining it as a community module... so if anyone wants to take my source and make a generic module for everyone, let me know.
  8. Boyan Barnev
    Boyan Barnev avatar
    1429 posts
    Registered:
    19 Sep 2016
    13 Jul 2012
    Link to this post
    Hi Mike,

    I am very happy to hear you have successfully implemented the desired functionality. Thank you very much for actively participating in our community and the willingness to share your project with the rest of the people reading these forums. As a token of appreciation we have updated your Telerik points accordingly.

    Regards,
    Boyan Barnev
    the Telerik team
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  9. Michael
    Michael avatar
    1 posts
    Registered:
    27 Oct 2010
    23 Jul 2012
    Link to this post
    Hi Michael,
    this sounds great, as I have exact the same problem. Would you share your code? :)
    Regards,
    Michael
  10. Michael
    Michael avatar
    67 posts
    Registered:
    16 Mar 2012
    23 Jul 2012
    Link to this post
    Well, I don't have anywhere public to place the ZIP file, and I'm not allowed to attach a ZIP file to this post. That's why I was hoping someone would take this and run with it, create an actual module, etc. All you'd need to do is maybe add some lines to the module file to add these fields to the ShortText field type so you don't have to type in the namespace all the time, etc., if that's possible (Haven't tried yet).

    I'm happy to send the ZIP file to someone who CAN post it here, etc.

    In the mean time, here's the code for the five files for an image field. File and Video fields aren't any different, they just change a few lines here and there to accommodate the different views you'd need there. Again, this is part of a module I wrote for us, so there may be references to the Module file in those, but it should just be for namespace resolution and virtual path stuff, which you can replace.

    ImageField.ascx
    <%@ Control %>
    <%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sf" %>
     
    <sf:ResourceLinks ID="resourcesLinks" runat="server" UseEmbeddedThemes="True" Theme="Default">
        <sf:ResourceFile JavaScriptLibrary="JQuery" />
        <sf:ResourceFile Name="Telerik.Sitefinity.Resources.Themes.Default.Styles.jQuery.jquery.ui.core.css"  Static="True"/>
        <sf:ResourceFile Name="Telerik.Sitefinity.Resources.Themes.Default.Styles.jQuery.jquery.ui.dialog.css" Static="True"/>
        <sf:ResourceFile Name="Telerik.Sitefinity.Resources.Themes.Default.Styles.jQuery.jquery.ui.theme.sitefinity.css"  Static="True"/>   
    </sf:ResourceLinks>
     
    <sf:ConditionalTemplateContainer ID="conditionalTemplate" runat="server">
        <Templates>
            <sf:ConditionalTemplate Left="DisplayMode" Operator="Equal" Right="Read" runat="server">  
                <sf:SitefinityLabel id="titleLabel_read" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfTxtLbl"></sf:SitefinityLabel>
                <sf:SitefinityLabel id="textLabel_read" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfTxtContent"></sf:SitefinityLabel>
     
                <asp:Image ID="image_read" runat="server" />
     
                <sf:SitefinityLabel id="descriptionLabel_read" runat="server" WrapperTagName="p" HideIfNoText="true" CssClass="sfDescription"></sf:SitefinityLabel>
                <sf:SitefinityLabel ID="exampleLabel_read" runat="server" WrapperTagName="P" HideIfNoText="true" CssClass="sfExample" />
            </sf:ConditionalTemplate>
            <sf:ConditionalTemplate Left="DisplayMode" Operator="Equal" Right="Write" runat="server">
                <sf:SitefinityLabel ID="titleLabel_write" runat="server" CssClass="sfTxtLbl" />
                <div class="sfPreviewImgFrame">
                    <asp:Image ID="image_write" runat="server" Width="160" Height="160" />
                </div>
     
                <sf:EditorContentManagerDialog runat="server" ID="asyncImageSelector" DialogMode="Image" Width="540" HostedInRadWindow="false" BodyCssClass="" />
                <asp:LinkButton ID="selectImageButton_write" OnClientClick="return false;" runat="server" CssClass="sfLinkBtn sfChange">
                    <span class="sfLinkBtnIn"><asp:Literal runat="server" ID="AddImageLiteral" Text="Select..." /></span>
                </asp:LinkButton>
                     
                <sf:SitefinityLabel id="descriptionLabel_write" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfDescription" />
                <sf:SitefinityLabel id="exampleLabel_write" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfExample" />
            </sf:ConditionalTemplate>
        </Templates>
    </sf:ConditionalTemplateContainer>

    ImageField.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Telerik.Sitefinity;
    using Telerik.Sitefinity.Web.UI;
    using Telerik.Sitefinity.Web.UI.Fields;
    using Telerik.Sitefinity.Web.UI.Fields.Enums;
     
    namespace NSC.Sitefinity.Modules.AssetPickerFields.ImageField
    {
        /// <summary>
        /// Sitefinity ImageField class.
        /// </summary>
        [FieldDefinitionElement(typeof(ImageFieldDefinitionElement))]
        public class ImageField : FieldControl
        {
            #region Constructors
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ImageField" /> class.
            /// </summary>
            public ImageField()
            {
                LayoutTemplatePath = layoutTemplatePath;
            }
     
            #endregion
     
            #region Properties
     
            /// <summary>
            /// Gets the title control.
            /// </summary>
            protected override WebControl TitleControl
            {
                get
                {
                    return TitleLabel;
                }
            }
     
            /// <summary>
            /// Gets the description control.
            /// </summary>
            protected override WebControl DescriptionControl
            {
                get
                {
                    return DescriptionLabel;
                }
            }
     
            /// <summary>
            /// Gets the example control.
            /// </summary>
            protected override WebControl ExampleControl
            {
                get
                {
                    return ExampleLabel;
                }
            }
     
            /// <summary>
            /// Gets the name of the layout template.
            /// </summary>
            protected override string LayoutTemplateName
            {
                get
                {
                    return null;
                }
            }
     
            /// <summary>
            /// Gets the reference to the label control that represents the title of the field control.
            /// </summary>
            /// <remarks>
            /// This control is mandatory only in write mode.
            /// </remarks>
            protected internal virtual Label TitleLabel
            {
                get
                {
                    return DisplayMode == FieldDisplayMode.Write ?
                        Container.GetControl<Label>("titleLabel_write", true) :
                        Container.GetControl<Label>("titleLabel_read", true);
                }
            }
     
            /// <summary>
            /// Gets the reference to the label control that represents the description of the field control.
            /// </summary>
            /// <remarks>
            /// This control is mandatory only in write mode.
            /// </remarks>
            protected internal virtual Label DescriptionLabel
            {
                get
                {
                    return DisplayMode == FieldDisplayMode.Write ?
                        Container.GetControl<Label>("descriptionLabel_write", true) :
                        Container.GetControl<Label>("descriptionLabel_read", true);
                }
            }
     
            /// <summary>
            /// Gets the reference to the label control that displays the example for this
            /// field control.
            /// </summary>
            /// <remarks>
            /// This control is mandatory only in the write mode.
            /// </remarks>
            protected internal virtual Label ExampleLabel
            {
                get
                {
                    return DisplayMode == FieldDisplayMode.Write ?
                        Container.GetControl<Label>("exampleLabel_write", true) :
                        Container.GetControl<Label>("exampleLabel_read", true);
                }
            }
     
            /// <summary>
            /// Gets or sets the value.
            /// </summary>
            /// <value>The value.</value>
            public override object Value
            {
                get
                {
                    return _imageId;
                }
                set
                {
                    if (value != null)
                    {
                        var val = new Guid(value.ToString());
                        _imageId = val;
     
                        if (val != Guid.Empty)
                        {
                            ReadImage.ImageUrl = App.WorkWith().Image(val).Get().MediaUrl;
                        }
                    }
                }
            }
     
            /// <summary>
            /// Gets the read image control.
            /// </summary>
            protected Image ReadImage
            {
                get { return Container.GetControl<Image>("image_read", false); }
            }
     
            /// <summary>
            /// Gets the write image control.
            /// </summary>
            protected Image WriteImage
            {
                get { return Container.GetControl<Image>("image_write", false); }
            }
     
            /// <summary>
            /// Gets the async image selector.
            /// </summary>
            protected EditorContentManagerDialog AsyncImageSelector
            {
                get { return Container.GetControl<EditorContentManagerDialog>("asyncImageSelector", false); }
            }
     
            /// <summary>
            /// Gets the select image button control.
            /// </summary>
            protected LinkButton SelectImageButton
            {
                get
                {
                    return Container.GetControl<LinkButton>("selectImageButton_write", false);
                }
            }
     
            #endregion
     
            #region Methods
     
            /// <summary>
            /// Initializes the controls.
            /// </summary>
            /// <param name="container">The container.</param>
            protected override void InitializeControls(GenericContainer container)
            {
                TitleLabel.Text = Title;
                ExampleLabel.Text = Example;
                DescriptionLabel.Text = Description;
     
                if (_imageId != Guid.Empty)
                {
                    ReadImage.ImageUrl = App.WorkWith().Image(_imageId).Get().MediaUrl;
                }
            }
     
            /// <summary>
            /// Gets the script descriptors.
            /// </summary>
            /// <returns>List of script descriptors.</returns>
            public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
            {
                var descriptors = new List<ScriptDescriptor>();
                var descriptor = base.GetScriptDescriptors().Last() as ScriptControlDescriptor;
     
                if (DisplayMode == FieldDisplayMode.Read)
                {
                    descriptor.AddElementProperty("readImage", ReadImage.ClientID);
                }
     
                if (DisplayMode == FieldDisplayMode.Write)
                {
                    descriptor.AddComponentProperty("asyncImageSelector", AsyncImageSelector.ClientID);
                    descriptor.AddElementProperty("selectImageButton", SelectImageButton.ClientID);
                    descriptor.AddElementProperty("writeImage", WriteImage.ClientID);
                    descriptor.AddProperty("imageServiceUrl", VirtualPathUtility.ToAbsolute("~/Sitefinity/Services/Content/ImageService.svc/"));
                }
     
                descriptors.Add(descriptor);
     
                return descriptors.ToArray();
            }
     
            /// <summary>
            /// Gets the script references.
            /// </summary>
            /// <returns>List of script references.</returns>
            public override IEnumerable<ScriptReference> GetScriptReferences()
            {
                var scripts = new List<ScriptReference>(base.GetScriptReferences());
     
                scripts.Add(new ScriptReference("Telerik.Sitefinity.Resources.Scripts.jquery-ui-1.8.8.custom.min.js", "Telerik.Sitefinity.Resources"));
                scripts.Add(new ScriptReference("Telerik.Sitefinity.Resources.Scripts.ajaxupload.js", "Telerik.Sitefinity.Resources"));
     
                scripts.Add(new ScriptReference(ScriptReference, typeof(AssetPickerFieldsModule).Namespace));
     
                return scripts;
            }
     
            #endregion
     
            #region Private members
     
            /// <summary>
            /// Image ID backing field.
            /// </summary>
            private Guid _imageId;
     
            /// <summary>
            /// layout template path.
            /// </summary>
            public static readonly string layoutTemplatePath = AssetPickerFieldsModule.EmbeddedResourceVirtualPath + typeof(ImageField).Namespace + ".ImageField.ascx";
     
            /// <summary>
            /// The script reference.
            /// </summary>
            public static readonly string ScriptReference = typeof(ImageField).Namespace + ".ImageField.js";
             
            #endregion
        }
    }

    ImageField.js
    Type.registerNamespace("NSC.Sitefinity.Modules.AssetPickerFields.ImageField");
     
    NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField = function (element) {
        NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.initializeBase(this, [element]);
     
        this._asyncImageSelector = null;
        this._selectImageButton = null;
        this._writeImage = null;
        this._readImage = null;
        this._imageServiceUrl = null;
     
        this._selectImageButtonClickDelegate = null;
     
        this._uploadDialog = null;
    };
     
    NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.prototype =
    {
        initialize: function () {
            NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.callBaseMethod(this, "initialize");
     
            this._selectImageButtonClickDelegate = Function.createDelegate(this, this._selectImageButtonClicked);
            if (this._selectImageButton) {
                $addHandler(this._selectImageButton, "click", this._selectImageButtonClickDelegate);
            }
     
            if (this._asyncImageSelector) {
                this._uploadDialog = jQuery(this._asyncImageSelector.get_element()).dialog({
                    autoOpen: false,
                    modal: true,
                    width: 540,
                    height: "auto",
                    closeOnEscape: true,
                    resizable: false,
                    draggable: false,
                    zIndex: 5000,
                    dialogClass: "sfSelectorDialog"
                });
     
                this._asyncImageSelectorInsertDelegate = Function.createDelegate(this, this._asyncImageSelectorInsertHandler);
                this._asyncImageSelector.set_customInsertDelegate(this._asyncImageSelectorInsertDelegate);
            }
        },
     
        dispose: function () {
            NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.callBaseMethod(this, "dispose");
     
            if (this._selectImageButton) {
                $removeHandler(this._selectImageButton, "click", this._selectImageButtonClickDelegate);
            }
     
            if (this._selectImageButtonClickDelegate) {
                delete this._selectImageButtonClickDelegate;
            }
        },
     
        /* --------------------  public methods ----------- */
     
        /* -------------------- events -------------------- */
     
        /* -------------------- event handlers ------------ */
     
        _selectImageButtonClicked: function (sender, args) {
            this._uploadDialog.dialog("open");
            var scrollTopHtml = jQuery("html").eq(0).scrollTop();
            var scrollTopBody = jQuery("body").eq(0).scrollTop();
            var scrollTop = ((scrollTopHtml > scrollTopBody) ? scrollTopHtml : scrollTopBody) + 50;
     
            jQuery(this._uploadDialog).parent().css({ "top": scrollTop });
     
            try {
                this._asyncImageSelector.get_uploaderView().get_altTextField().set_value("");
            }
            catch (ex) { }
     
            jQuery(this._asyncImageSelector.get_uploaderView().get_settingsPanel()).hide();
     
            return false;
        },
     
        /* -------------------- private methods ----------- */
     
        _asyncImageSelectorInsertHandler: function (selectedItem) {
            if (selectedItem) {
                this.set_value(selectedItem.Id);
                this._uploadDialog.dialog("close");
            }
        },
     
        // Gets the value of the image control.
        //    get_value: function () {
        //        debugger;
        //        var value = NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.callBaseMethod(this, "get_value");
        //        return value;
        //    },
     
        // Sets the value of the image control.
        set_value: function (value) {
            if (this._displayMode == 0) {
                return;
            }
     
            var imageControl = this._writeImage;
            if (value && value.toString() != "00000000-0000-0000-0000-000000000000") {
                var id = value;
                var url = this._imageServiceUrl + "live/" + id + "/";
                var data = null;
     
                $.ajax({
                    url: url,
                    success: function (data) {
                        var imageUrl = data["Item"]["MediaUrl"];
     
                        if (imageControl) {
                            jQuery(imageControl).attr("src", imageUrl);
                        }
                    }
                });
            } else {
                if (imageControl) {
                    jQuery(imageControl).attr("src", "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==");
                }
            }
     
            NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.callBaseMethod(this, "set_value", [value]);
        },
     
        /* -------------------- properties ---------------- */
     
        get_asyncImageSelector: function () {
            return this._asyncImageSelector;
        },
        set_asyncImageSelector: function (value) {
            this._asyncImageSelector = value;
        },
     
        get_selectImageButton: function () {
            return this._selectImageButton;
        },
     
        set_selectImageButton: function (value) {
            this._selectImageButton = value;
        },
     
        get_writeImage: function () {
            return this._writeImage;
        },
     
        set_writeImage: function (value) {
            this._writeImage = value;
        },
     
        get_readImage: function () {
            return this._readImage;
        },
     
        set_readImage: function (value) {
            this._readImage = value;
        },
     
        get_imageServiceUrl: function () {
            return this._imageServiceUrl;
        },
     
        set_imageServiceUrl: function (value) {
            this._imageServiceUrl = value;
        }
    };
     
    NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField.registerClass("NSC.Sitefinity.Modules.AssetPickerFields.ImageField.ImageField", Telerik.Sitefinity.Web.UI.Fields.FieldControl);

    ImageFieldDefinition.cs
    using Telerik.Sitefinity.Configuration;
    using Telerik.Sitefinity.Web.UI.Fields.Definitions;
     
    namespace NSC.Sitefinity.Modules.AssetPickerFields.ImageField
    {
        public class ImageFieldDefinition : FieldControlDefinition
        {
            #region Constuctors
            /// <summary>
            /// Initializes a new instance of the <see cref="ImageFieldDefinition" /> class.
            /// </summary>
            public ImageFieldDefinition()
            {
            }
     
            /// <summary>
            /// Initializes a new instance of the <see cref="ImageFieldDefinition" /> class.
            /// </summary>
            /// <param name="configDefinition">The config definition.</param>
            public ImageFieldDefinition(ConfigElement configDefinition)
                : base(configDefinition)
            {
            }
     
            #endregion
        }
    }

    ImageFieldDefinitionElement.cs
    using System;
    using Telerik.Sitefinity.Configuration;
    using Telerik.Sitefinity.Web.UI;
    using Telerik.Sitefinity.Web.UI.Fields.Config;
     
    namespace NSC.Sitefinity.Modules.AssetPickerFields.ImageField
    {
        public class ImageFieldDefinitionElement : FieldControlDefinitionElement
        {
            #region Constructors
            /// <summary>
            /// Initializes a new instance of the <see cref="ImageFieldDefinitionElement" /> class.
            /// </summary>
            /// <param name="parent">The parent.</param>
            public ImageFieldDefinitionElement(ConfigElement parent)
                : base(parent)
            {
            }
     
            #endregion
     
            #region FieldControlDefinitionElement members
     
            public override DefinitionBase GetDefinition()
            {
                return new ImageFieldDefinition(this);
            }
     
            #endregion
     
            #region IFieldDefinition members
     
            public override Type DefaultFieldType
            {
                get
                {
                    return typeof(ImageField);
                }
            }
     
            #endregion
        }
    }

  11. Sheena
    Sheena avatar
    11 posts
    Registered:
    24 Sep 2012
    24 Sep 2012
    Link to this post
    Hello Stephen, this is very interesting. Thanks
11 posts, 0 answered