Add "ImageField" as custom field for Blogs, make i

Posted by Community Admin on 04-Aug-2018 05:23

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

All Replies

Posted by Community Admin on 04-Jun-2012 00:00

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.

Posted by Community Admin on 04-Jun-2012 00:00

ImageField (selector) can provide the selected GUID to the client.
Accessed from:  .get_selectedImageItem().Id

Posted by Community Admin on 04-Jun-2012 00:00

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?

Posted by Community Admin on 04-Jun-2012 00:00

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...

Posted by Community Admin on 29-Jun-2012 00:00

I will second that this needs to be built in. It is already a built in option for items built using the Module Builder.

Posted by Community Admin on 02-Jul-2012 00:00

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.

Posted by Community Admin on 12-Jul-2012 00:00

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.

Posted by Community Admin on 13-Jul-2012 00:00

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

Posted by Community Admin on 23-Jul-2012 00:00

Hi Michael,
this sounds great, as I have exact the same problem. Would you share your code? :)
Regards,
Michael

Posted by Community Admin on 23-Jul-2012 00:00

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
    

Posted by Community Admin on 24-Sep-2012 00:00

Hello Stephen, this is very interesting. Thanks

This thread is closed