Selecting documents in Field Controls with EditorContentManagerDialog

Selecting documents in Field Controls with EditorContentManagerDialog

Posted on February 08, 2012 0 Comments

The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.

There have been a lot of requests for a sample on Field Controls with a document selector, so I decided to show you how to make use of Sitefinity's EditorContentManagerDialog to select content inside field controls. This sample is simplified as much as it could be - there are no custom selectors, no hosting of dialogues inside windows - just the built-in EditorContentManagerDialog inside a field control. 
The sample is built, using Slavo's ThumbnailSelectorField (for simplicity, the names inside have not been changed, so that it can be easier for you to make the connection between the two controls), so I won't be explaining in detail how field controls work, as this is already done by Slavo in his blog post
In his sample, Slavo had a field control, an image selector and a dialogue. What I did was remove the selector and the dialogue and use only the field control. Inside, I put an EditorContentManagerDialog, which already has selectors inside, and even has different modes for selecting files/images, so it would be easy for you to transform this into an Image selector, as well.
Here's how I modified the template of the field control:

<%@ Control Language="C#" AutoEventWireup="true" %>
 
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sf" %>
<%@ Register Assembly="ThumbnailSelectorField" Namespace="Telerik.Sitefinity.Samples" TagPrefix="samples" %>
 
<sf:ResourceLinks ID="resourcesLinks" runat="server">
    <sf:ResourceFile JavaScriptLibrary="JQuery">
    </sf:ResourceFile>
</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="false" CssClass="sfTxtLbl"></sf:SitefinityLabel>
            <sf:SitefinityLabel id="textLabel_read" runat="server" WrapperTagName="div" HideIfNoText="false" CssClass="sfTxtContent"></sf:SitefinityLabel>
            <sf:SitefinityHyperLink id="documentLink" runat="server" />
            <sf:SitefinityLabel id="descriptionLabel_read" runat="server" WrapperTagName="p" HideIfNoText="false" 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" />
            <asp:LinkButton ID="expandButton_write" runat="server" OnClientClick="return false;" CssClass="sfOptionalExpander" />
            <asp:Panel ID="expandableTarget_write" runat="server" CssClass="sfFieldWrp">
                 
                <sf:EditorContentManagerDialog runat="server" ID="asyncImageSelector" DialogMode="Document" Width="540" HostedInRadWindow="false"  BodyCssClass="" />
                <asp:TextBox ID="textBox_write" runat="server" CssClass="sfTxt" />
                <asp:LinkButton ID="replaceImage" 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" />
            </asp:Panel>
        </sf:ConditionalTemplate>
    </Templates>
</sf:ConditionalTemplateContainer>

As you can see I replaced the <img> control in Read Mode with a Sitefinity Hyperlink,which will be used as a link to the document and I also replaced the Rad WindowManager with the EditorContentManagerDialog.
Then in the codefile of my field, I added references to the new control, removed the old ones and changed the way Documents are displayed in Read mode:

public override object Value
        {
            get
            {
                var val = string.Empty;
                switch (this.DisplayMode)
                {
                    case FieldDisplayMode.Read:
                        val = this.DocumentLink.NavigateUrl;
                        break;
                    case FieldDisplayMode.Write:
                        val = this.TextBoxControl.Text;
                        break;
                }
                return val;
            }
            set
            {
                if (this.ChildControlsCreated)
                {
                    switch (this.DisplayMode)
                    {
                        case FieldDisplayMode.Write:
                            this.TextBoxControl.Text = value as string;
                            break;
 
                        case FieldDisplayMode.Read:
                            var imageId = new Guid(value.ToString());
                            var document = App.WorkWith().Document(imageId).Get();
                            this.DocumentLink.NavigateUrl = document.Url;
                            this.DocumentLink.Text = document.Title;
                            
                            break;
                    }
                    base.Value = null;
                }
                else
                {
                    base.Value = value;
                }
            }
        }

protected EditorContentManagerDialog AsyncImageSelector
        {
            get
            {
                return this.Container.GetControl<EditorContentManagerDialog>("asyncImageSelector", false);
            }
        }

and I also added the dialog to the ScriptDescriptors, so I can have a reference object of it inside the client component:

public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        {
            var lastDescriptor = (ScriptControlDescriptor)base.GetScriptDescriptors().Last();
 
            if (this.DisplayMode == FieldDisplayMode.Write)
            {
                
                lastDescriptor.AddElementProperty("replaceImageButtonElement", this.ReplaceImageButton.ClientID);
                lastDescriptor.AddComponentProperty("asyncImageSelector", this.AsyncImageSelector.ClientID);
                
            }
            if (this.DisplayMode == FieldDisplayMode.Read)
            {
                lastDescriptor.AddElementProperty("imageControl", this.DocumentLink.ClientID);
            }
 
            yield return lastDescriptor;
        }

Finally, I modified the javascript part of the field to get the selected item from the dialog and set its ID as a Value of the field control:

On initialize I create all the needed handlers and delegates (and then remove them on dispose):

initialize: function () {
        Telerik.Sitefinity.Samples.SimpleImageField.callBaseMethod(this, "initialize");
        this._replaceImageButtonElementClickDelegate = Function.createDelegate(this, this._replaceImageButtonElementClicked);
        if (this._replaceImageButtonElement) {
            $addHandler(this._replaceImageButtonElement, "click", this._replaceImageButtonElementClickDelegate);
        }
 
        this._onLoadDelegate = Function.createDelegate(this, this._onLoad);
        Sys.Application.add_load(this._onLoadDelegate);
        this._onUnloadDelegate = Function.createDelegate(this, this._onUnload);
        Sys.Application.add_unload(this._onUnloadDelegate);
 
        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);
        }
 
 
    },

The tree delegates are for opening the dialogue on button click (replaceImageButtonElementClicked), setting the Read mode value (_set_readModeValue) and setting the selected item's ID to the value of the field on the dialogue's item selected event (_asyncImageSelectorInsertHandler).

replaceImageButtonElementClicked: 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 ----------- */
 
    _set_readModeValue: function (value) {
        if (value === undefined || value == null) {
            this._clearLabel();
        }
 
    },
 
    _asyncImageSelectorInsertHandler: function (selectedItem) {
 
        if (selectedItem) {
            this.set_value(selectedItem.Id);
            this._uploadDialog.dialog("close");
 
 
        }
    },

This can be easily turned into an image selector, as I've already stated, by just changing the DialogMode property of the EditorContentManager dialog to "Image" and changing the displaying controls for Read Mode.

Installation instructions (basically they are almost the same as in Slavo's post):

1) Extract the files into a folder
2) Add them as an external project to your Sitefinity solution
3) Copy/paste the global.asax file into SitefinityWebApp (or if you already have an existing one, add the code to it) or  manually register a virtual path ~/ThumbnailSelector/* (this is used for the template of the control). It can be done from the Backend -> Administration >> Settings >> Advanced >> VirtualPathSettings.
4) Set the build action for the .ascx and .js files to EmbeddedResource
5) Add a reference to the control's project in SitefinityWebApp
6) Add the .js file as a web resource in AssemblyInfo.cs of SitefinityWebApp:

[assembly: WebResource("SitefinityWebApp.SimpleImageField.SimpleImageField.js", "application/x-javascript")]

7) Compile and run your project

8) Create a custom field in any module (works for ECommerce, as well) and specify a custom widget for entering data. The type of the custom widget should be Telerik.Sitefinity.Samples.SimpleImageField

9) For read mode, you can add the SimpleImageField in your content-widget templates like this (assuming the field is called Thumbnail):

<samples:SimpleImageField runat="server" DisplayMode="Read" Value='<%# Eval("Thumbnail")%>' />

Download the control from here:

DocumentSelectorField

progress-logo

The Progress Team

View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation