One of the problems with creating custom user controls is that it is difficult for your user to add text and image content in a wysiwyg fashion. There simple examples of usercontrols that employ a custom webeditor but in reality they have left much to be desired. I have found that the images don't work in the editor and the styles are very messed up. I was able to solve most of these issues and get a more desired(ie. usable) result without a huge amount of up-front effort.
By using the LoadControl function I was able to instantiate the control that was used in the ControlTemplates directory for the RadEditor. Also I update the css to make the image dialogs show up. If you examine the following code you will get a feel for what I have done and be able to apply it to different controls that will really make easy the process of authoring and getting your websites into the customers hands. You will also be able to have usable controls at the same time. Too good to be true?
The following code can be put in the App_Code folder but I recommend creating a separate project for it unless you can compile Sitefinity in 5 seconds. If you are doing work on the control the whole website has to be rebuilt whenever you make changes.
The next part is to have a control in the ~/UserControls/ directory to load. I used the GenericContent edit template as a base to start from the UserControl code looks like this.
<%@ Control Language="C#" ClassName="CustomEditor" %>
<
style
type
=
"text/css"
>
.Dialog
{
MARGIN-LEFT: -64px! important;
WIDTH: 748px! important
}
.Dialog fieldset
{
height:420px !important;
}
.RadWindow
{
z-index:15001 !important;
}
.rwTable
{
height:498px !important;
margin-top:0px !important;
}
</
style
>
<%@ Register TagPrefix="sf" Namespace="Telerik.Cms.Engine.WebControls" Assembly="Telerik.Cms.Engine" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Cms.Engine.WebControls.Admin" Assembly="Telerik.Cms.Engine" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Cms.Web.UI" Assembly="Telerik.Cms.Web.UI" %>
<
telerik:RadEditor
id
=
"Editor"
runat
=
"server"
contentareacssfile
=
"~/Sitefinity/Admin/Themes/Default/AjaxControlsSkins/Sitefinity/EditorContentArea.css"
toolsfile
=
"~/Sitefinity/Admin/ControlTemplates/EditorToolsFile.xml"
skin
=
"WebBlue"
newlinebr
=
"False"
width
=
"95%"
ContentFilters
=
"EncodeScripts,FixUlBoldItalic,FixEnclosingP,IECleanAnchors,MozEmStrong,ConvertFontToSpan,ConvertToXhtml,IndentHTMLContent"
>
<
ImageManager
ViewPaths
=
"~/Images"
UploadPaths
=
"~/Images"
DeletePaths
=
"~/Images"
/>
<
MediaManager
ViewPaths
=
"~/Files"
UploadPaths
=
"~/Files"
DeletePaths
=
"~/Files"
/>
<
FlashManager
ViewPaths
=
"~/Files"
UploadPaths
=
"~/Files"
DeletePaths
=
"~/Files"
/>
<
DocumentManager
ViewPaths
=
"~/Files"
UploadPaths
=
"~/Files"
DeletePaths
=
"~/Files"
/>
<
CssFiles
>
<
telerik:EditorCssFile
Value
=
"~/Sitefinity/Admin/Themes/Default/AjaxControlsSkins/Sitefinity/EditorCssFile.css"
/>
</
CssFiles
>
</
telerik:RadEditor
>
<
script
type
=
"text/javascript"
>
Telerik.Web.UI.Editor.CommandList["LibraryImageManager"] = function(commandName, editor, args) {
var editorArgs = editor.getSelectedElement();
if (!editorArgs.nodeName || typeof (editorArgs.nodeName) == "undefined" || editorArgs.nodeName != "A")
editorArgs = editor.getSelection();
var myCallbackFunction = function(sender, args) {
if (typeof (editorArgs.nodeName) != "undefined" && editorArgs.nodeName == "IMG")
args.parentNode.replaceChild(editorArgs, args);
else {
var cloned = args.cloneNode(true);
var div = args.ownerDocument.createElement("DIV");
div.appendChild(cloned);
editorArgs.pasteHtml(div.innerHTML);
}
}
editor.showExternalDialog(
'<%= ((Telerik.Cms.Web.CmsPageBase)Page).ResolveCmsUrl("~/Sitefinity/UserControls/Dialogs/ImageEditorDialog.aspx") %>',
editorArgs,
750,
600,
myCallbackFunction,
null,
'ImageLibraryDialog',
true,
Telerik.Web.UI.WindowBehaviors.Close + Telerik.Web.UI.WindowBehaviors.Move,
false,
true)
};
Telerik.Web.UI.Editor.CommandList["LibraryDocumentManager"] = function(commandName, editor, args) {
var editorArgs = editor.getSelectedElement();
if (!editorArgs.nodeName || typeof (editorArgs.nodeName) == "undefined" || editorArgs.nodeName != "A")
editorArgs = editor.getSelection();
var myCallbackFunction = function(sender, args) {
if (typeof (editorArgs.nodeName) != "undefined" && editorArgs.nodeName == "A")
args.parentNode.replaceChild(editorArgs, args);
else {
var cloned = args.cloneNode(true);
var div = args.ownerDocument.createElement("DIV");
div.appendChild(cloned);
editorArgs.pasteHtml(div.innerHTML);
}
}
editor.showExternalDialog(
'<%= ((Telerik.Cms.Web.CmsPageBase)Page).ResolveCmsUrl("~/Sitefinity/UserControls/Dialogs/DocumentEditorDialog.aspx") %>',
editorArgs,
750,
600,
myCallbackFunction,
null,
'ImageLibraryDialog',
false,
Telerik.Web.UI.WindowBehaviors.Close + Telerik.Web.UI.WindowBehaviors.Move,
false,
true)
};
Telerik.Web.UI.Editor.CommandList["LinkManager"] = function(commandName, editor, args) {
var editorArgs = editor.getSelectedElement();
if (!editorArgs.nodeName || typeof (editorArgs.nodeName) == "undefined" || editorArgs.nodeName != "A") {
var sel = editor.getSelection();
editorArgs = sel;
editorArgs.Html = sel.getHtml();
editorArgs.Text = sel.getText();
}
var myCallbackFunction = function(sender, args) {
if (typeof (editorArgs.nodeName) != "undefined" && editorArgs.nodeName == "A")
args.parentNode.replaceChild(editorArgs, args);
else {
var cloned = args.cloneNode(true);
var div = args.ownerDocument.createElement("DIV");
div.appendChild(cloned);
editorArgs.pasteHtml(div.innerHTML);
}
}
editor.showExternalDialog(
'<%= ((Telerik.Cms.Web.CmsPageBase)Page).ResolveCmsUrl("~/Sitefinity/UserControls/Dialogs/LinksDialog.aspx") %>',
editorArgs,
750,
600,
myCallbackFunction,
null,
'ImageLibraryDialog',
false,
Telerik.Web.UI.WindowBehaviors.Close + Telerik.Web.UI.WindowBehaviors.Move,
false,
true)
};
Telerik.Web.UI.Editor.CommandList["SetLinkProperties"] = function(commandName, editor, args) {
var editorArgs = editor.getSelectedElement();
if (!editorArgs.nodeName || typeof (editorArgs.nodeName) == "undefined" || editorArgs.nodeName != "A")
editorArgs = editor.getSelection();
var myCallbackFunction = function(sender, args) {
if (typeof (editorArgs.nodeName) != "undefined" && editorArgs.nodeName == "A")
args.parentNode.replaceChild(editorArgs, args);
else {
var cloned = args.cloneNode(true);
var div = args.ownerDocument.createElement("DIV");
div.appendChild(cloned);
editorArgs.pasteHtml(div.innerHTML);
}
}
editor.showExternalDialog(
'<%= ((Telerik.Cms.Web.CmsPageBase)Page).ResolveCmsUrl("~/Sitefinity/UserControls/Dialogs/LinksDialog.aspx") %>',
editorArgs,
750,
600,
myCallbackFunction,
null,
'ImageLibraryDialog',
false,
Telerik.Web.UI.WindowBehaviors.Close + Telerik.Web.UI.WindowBehaviors.Move,
false,
true)
};
var oldFunction = Telerik.Web.UI.Editor.CommandList["ToggleScreenMode"]; //save the original Paste function
Telerik.Web.UI.Editor.CommandList["ToggleScreenMode"] = function(commandName, editor, args) {
oldFunction(commandName, editor, args);
var bd = document.getElementsByTagName("body")[0];
if (/fullScreenMode/.test(bd.className)) {
var rep = bd.className.match(' ' + 'fullScreenMode') ? ' ' + 'fullScreenMode' : 'fullScreenMode';
bd.className = bd.className.replace(rep, '');
} else {
bd.className += bd.className ? ' ' + 'fullScreenMode' : 'fullScreenMode';
}
};
// automated tests helper function
function InsertTextArea() {
var editor = $find('<%=Editor.ClientID%>');
editor.set_html('<
textarea
id
=
"myTableToFind"
style
=
"overflow:hidden; height: 300px; width: 500px;"
border
=
"none"
></
textarea
>');
}
</
script
>
Not much to explain here but to put it into a UserControl Called CustomEditor.ascx. The other part is that understand that the name of the Editor matters ("Editor") in this example. It is used in the custom WebEditor and there is a Editor.ClientID reference in the javascript. You can put this control in your sitefinity project (not in a separate project).
Now to wrap things up you Build a custom UserControl of your choice and add a public property.
Here you can see that I have added a custom WebEditor attribute to the property Venue.
The end result is that when you add your UserControl to sitefinity and drag it onto a content area you can select edit and you will have a button that pops up a nice editor to fill in the Venue value for the user control. This is something that is not available out of the box but is a great addition to the drag and drop support that Sitefinity has so conveniently added.
I will add to this later and make it more clear. If you have any difficulties implementing this please post a comment. Maybe if someone wants to wrap up the usercontrol part of the sample into the external project so that it is a nice managed dll that would be an excellent feat.