UPDATE 2: Improvements and extensions to this thumbnail selector are included in a newer blog post.
UPDATE: In the comments to this blog post, some people reported issues with running the sample in Sitefinity 4.1. Those issues have been fixed. The download links in the post have been updated and point to the new version of the sample containing the fixes. If someone is still running versions of Sitefinity before 4.1, you can download the initial version from here. The installation instructions have also been updated with the correct file names.
In my previous blog post I showed you how you can create a simple image selector. Today, we are going to use it to select thumbnails for news items and display them on a page. There are several controls that we need for the purpose, but before we discuss the implementation, you can take a look at the result we are aiming for in this video.
Walkthrough
You can download the source code for this example from here. Here is a list of what we will need to implement to cover the scenario shown in the above video:
- The control used to select images from the previous post.
- A dialog that displays the control from step 1 and returns the selected image:
- A control used to save the thumbnail URL as a custom field in the news item:
- A control used to display the thumbnail in the public template for news items. This is going to be the same control we create in step 3.
Note: All controls that we build in this blog post have a corresponding client component. More information about how to build client components can be found on MSDN.
A Dialog to Select a Thumbnail
Dialogs have a special role in Sitefinity. They are used everywhere in the backend when editing, creating and selecting items. They provide the infrastructure for opening specialized windows and returning results. How you can use all the goodness that dialogs provide for you is a topic for another post. For our specific purpose, you can think of the dialog as a simple control, which is registered in Sitefinity with a specific URL and opens in a RadWindow.
Our dialog is just a wrapper, that contains the simple image selector we built last week. Here's the template:
<
div
>
<
samples:SimpleImageSelector
ID
=
"imageSelector"
runat
=
"server"
>
</
samples:SimpleImageSelector
>
</
div
>
<
div
class
=
"sfClearer"
>
<
asp:HyperLink
ID
=
"lnkDone"
runat
=
"server"
NavigateUrl
=
"javascript:void(0);"
CssClass
=
"sfLinkBtn sfSave"
>
<
span
class
=
"sfLinkBtnIn"
>Done</
span
>
</
asp:HyperLink
> or
<
asp:HyperLink
ID
=
"lnkCancel"
runat
=
"server"
NavigateUrl
=
"javascript:void(0);"
Text
=
"Cancel"
CssClass
=
"sfCancel"
></
asp:HyperLink
>
</
div
>
_doneLinkClicked:
function
(sender, args) {
var
selectedValue =
this
.get_imageSelector().get_selectedImageUrl();
if
(!selectedValue || selectedValue ===
""
) {
alert(
"No image selected."
);
}
else
{
dialogBase.close(selectedValue);
}
},
_cancelLinkClicked:
function
(sender, args) {
dialogBase.close();
},
This is all that we need to do in our dialog - get the URL of the image from the selector, and return it as a result from the dialog. However, we also need to let Sitefinity know about our dialog. This is done by registering the dialog in our Global.asax file:
protected
void
Application_Start(
object
sender, EventArgs e)
{
Telerik.Sitefinity.Abstractions.Bootstrapper.Initialized +=
new
EventHandler<Telerik.Sitefinity.Data.ExecutedEventArgs>(Bootstrapper_Initialized);
}
protected
void
Bootstrapper_Initialized(
object
sender, Telerik.Sitefinity.Data.ExecutedEventArgs args)
{
Telerik.Sitefinity.Web.UI.Dialogs.RegisterDialog<Telerik.Sitefinity.Samples.SimpleImageSelectorDialog>();
}
A Custom Field Control to Save the Thumbnail URL in the News Item
This is the tricky part, but once you've done it once, it's quite easy. The form through which you edit news items is composed of the so-called field controls. One field control has two main responsibilities - to provide user interface for editing and displaying a single property of a content item. In our case, the content item is a news item, the property is the thumbnail (created as a custom field). Both the TextBox in which you enter the URL, and the thumbnail that you see on the public page are part of the same field control we will create - the former we call Write mode (the user writes the value of the property), the latter Read mode (the value of the property is read and displayed).
Most of the required functionality has already been implemented in a regular text field control. TextField is what lets you edit titles for news items, for example. The different UI in our case is a link that we will display to open the dialog when in write mode (backend), and the image we are going to show when in read mode (frontend). So we inherit TextField, and override what we need to account for the different functionality.
Although the code might look like a lot, most of it is required to hook things up. The most important part that actually does the work is overriding the Value property on the server and on the client:
public
override
object
Value
{
get
{
var val =
string
.Empty;
switch
(
this
.DisplayMode)
{
case
FieldDisplayMode.Read:
val =
this
.ImageControl.ImageUrl;
break
;
case
FieldDisplayMode.Write:
val =
this
.TextBoxControl.Text;
break
;
}
return
val;
}
...
}
Here's the part on the client that grabs the URL from the dialog and populates the TextBox:
_set_readModeValue:
function
(value) {
if
(value === undefined || value ==
null
) {
this
._clearLabel();
}
else
{
if
(
this
._imageControl !=
null
) {
jQuery(
this
._imageControl).attr(
"src"
, value);
}
}
},
...
_windowClosed:
function
(sender, args) {
var
imageUrl = args.get_argument();
if
(imageUrl && imageUrl !==
""
) {
this
.set_value(imageUrl);
}
},
All the rest is getting references to controls in the template, passing values from the server to the client and opening the dialog itself. You can look at the details in the download.
Up to this point, you've created everything Sitefinity needs to select and persist the value of the thumbnail. Now the only thing left is to let it know where to find your controls together with any metadata you may need to pass. For this purpose, it uses control definitions (they define your field control, so Sitefinity knows how to use it). Ivan Osmak described the concept in this blog post. For our purpose, we don't need anything special, so we just inherit from the base definition for TextField. Once this is done, Sitefinity should be able to find you custom field, display it when you edit news items, and show the selected thumbnail in any news item template.
Installation Instructions
- Download the source code for this example and extract it in your project's main folder.
- Open the project in Visual Studio as a web application, and include the files in the project.
- Set the build action of all .js files to "EmbeddedResource"
- Add the following lines to the AssemblyInfo.cs file in SitefinityWebApp:
[assembly: WebResource(
"SitefinityWebApp.ImageSelector.SimpleImageSelector.js"
,
"application/x-javascript"
)]
[assembly: WebResource(
"SitefinityWebApp.SimpleImageField.SimpleImageField.js"
,
"application/x-javascript"
)]
[assembly: WebResource(
"SitefinityWebApp.SimpleImageField.SimpleImageSelectorDialog.js"
,
"application/x-javascript"
)]
- Compile and run your project.
- Create a custom field in News for the thumbnail (as shown in the video) and specify a custom widget for entering data. The type of the custom widget should be Telerik.Sitefinity.Samples.SimpleImageField.
- Edit the list template for news and add the control to display the thumbnail (as shown in the video):
<
samples:SimpleImageField
runat
=
"server"
DisplayMode
=
"Read"
Value='<%# Eval("Thumbnail")%>' />
Conclusion
This is only scratching the surface of how you can extend Sitefinity. Concepts like Field Controls and Control Definitions allow you to go crazy with your ideas and extend the built-in modules to support custom scenarios. Expect more thorough examination of those topics in the coming weeks. Meanwhile, we'd love to hear your feedback in the forums.