How do I...RadEditor
Hi,
I want to make a couple of changes to the RadEditor, but im not sure how to do it in V4.
1) I want to change which RadEditor buttons are within the "basic" and "more advanced" views. For example, I want to move the Paragraph style dropdown into the basic options. Globally if possible so it is implemented everywhere within SiteFinity that uses the RadEditor.
2) I want to actually hide the "More advanced formatting" view unless the logged-in user is a member of the Administrators role. again, globally.
3) Every Control Designer has a "Simple" and "Advanced" view. Again, I want to hide the Advanced view from anyone that is not a member of the Administrators role. I had really hoped this was going to be in V4 as I saw it asked for a lot of times in V3.
4) Finally...The RadEDitor has a HTML and Design view. I want to hide the HTML view from users that are not members of the administrators role.
Thanks in advance
higgsy
Hello higgsy,
Please take a look at this post that explains how to map and modify the ContentBlock control. You can change the RadEditor properties using its specific API. To work with Sitefinity users you can use UserManage, SecurityManager and RoleManager classes.
If there are any questions, let me know.
Best wishes,
Ivan Dimitrov
the Telerik team
Hi Ivan,
Thanks for the response, however I need a little more information.
1) If I map the ContentBlockControl I don't have access to the code-behind/class, therefore I can't work with the RadEditors API, or work with Sitefinity's users. What do you suggest? Do I in fact need to create my own contentblockdesigner?
2) The RadEditor has this new button "More advanced formatting" - where in the RadEditors config is it defined which tools should appear in "basic formatting" and "advanced formatting" views?
3) Is it possible to disable the Advanced views of Control Designers - there is no reason Content Editors should be using the Advanced view.
4) If i want to make changes to the RadEditor sitewide surely i actually need to be changing the HtmnlField control?
Thanks
higgsy
Hi higgsy,
1. You can access the RadEditor from HtmlField control
2. More advanced formatting is implementation inside HtmlField
3. There is a way to hide the Advanced button programmatically from the client, but this requires custom control designer and client side part for the designer.
refreshUI:
function
()
var
p =
this
.get_propertyEditor();
jQuery(p.get_advancedModeButton()).hide();
,
Hi Ivan/Radoslav,
Apologies but I still need more detailed information.
1) Ok. But I need to change the RadEditor referenced by HtmlField sitewide. So how do I remap HtmlField? Is it a viewmap I need to map?
2) I looked at the HtmlField class from within Telerik.sitefinity.dll and I could not see anywhere that referenced a tools file. So how will I actually change the tools that are loaded into the RadEditor?
3) Ok - thats a real shame. Its something I saw asked for time and time again in 3.7 and I dont suppose that requirement has gone away - in my eyes, there is no reason that a non-administrator should be using the advanced view. I'll raise a feature request.
4) Relates to 1 & 2 really.
Thanks
higgsy
Hi higgsy,
Once you map the template of the CotnentBlock as suggested to you in the first reply you have access to the HtmlField control and the wrapped RadEditor
htmlEditor.Editor.ToolsFile
I do not see what the problem here would be with accessing this property. Another option for mapping the tools file would be using ApparanceConfig file with content like this:
<?xml version="1.0" encoding="utf-8"?>
<appearanceConfig xmlns:config="urn:telerik:sitefinity:configuration" xmlns:type="urn:telerik:sitefinity:configuration:type" config:version="4.0.4042.33518">
<editorConfigurations>
<add value="~/EditorToolsFileAll.xml" key="toolsFile" />
</editorConfigurations>
</appearanceConfig>
And for the <sf:HtmlField> definition specify the following attributes:
EditorToolsConfiguration="Custom"
EditorToolsConfigurationKey="toolsFile"
Ivan,
This might be my misunderstanding, but do the modules i.e. news/blogs/events etc use the content block, or the HtmlField? It was my assumption that it would use the HtmlField, at which point I need to get at the HtmlField not the Content Block.
"Once you map the template of the CotnentBlock as suggested to you in the first reply you have access to the HtmlField control and the wrapped RadEditor"
How would I have access? Only in the markup, or are you suggesting I map an usercontrol with code-behind?
Thanks
higgsy
Hi higgsy,
Currently it is not possible to change the appearance or any logic of HTML filed from one place. The backend uses definitions where the HtmlField is represented by HtmlFieldElement
The solution here would be creating a custom class that inherits from HtmlField and replace similar to the way described in this post.
In the post you will find an attachment. It contains DefinitionManager class. It provides you with a method to replace any kind of existing with any kind of new field for the specified module. You will notice there how to traverse the hierarchy of the definitions engine to find the fields which should be replaced.
Greetings,
Ivan Dimitrov
the Telerik team
Hi Ivan,
I am sorry - but your responses have not answered my questions.
1) The method you describe talks about the ContentBlockDesigner, but I want it changed everywhere within Sitefinity that uses the RadEditor. I appreciate you are saying this cannot be done, but then in which case I need to know how to get at the template for each module i.e. Blogs/ News / Events - they all use the RadEditor.
2) I have asked how do I determine which tools are shown under "basic" or "more advanced options". I have mapped a tools file, but how do I set certain tools to be within advanced?
3) Finally, in your last response you referred to a post - "The solution here would be creating a custom class that inherits from
HtmlField and replace similar to the way described in this post." - but replace what with what? Come on, SF4 is new and there is not documentation for it, you are talking about an advanced topic here without any guidance.
I would really appreciate a detailed response - many of your responses assume I am a V4 expert - its a new product, so quick responses will really not answer the questions, hence the reason this ticket has been open so long.
Regards,
Al
The Appearance.config sounds really interesting. I would love to see more details on that in the designer docs.
I think I am trying to do the same as higgsy. I want to set my own properties for the RadEditor in the "content" field while creating a News item. I see I can go to "Content > News > Settings" and then go to "News > Controls > NewsBackend > Views > NewsBackendInsert > Sections > MainSection > Fields > Content". This seems like the properties of the RadEditor and works great (I set HTML for the HtmlFieldEditModes property and worked). Unfortunately, there is no field to set your own toolbar. Is this the right place I should be looking at?
Hi higgsy,
1.You can do it globally - for the entire website by mapping
Telerik.Sitefinity.Web.UI.Fields.HtmlField through the configuration. Ia m sending you the template for HtmlField which you can modify. The template gives you access to the RadEditor control, so you can set the properties you want.
<%@ Control Language="C#" %>
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sf" %>
<
sf:ConditionalTemplateContainerID
=
"conditionalTemplate"
runat
=
"server"
>
<
Templates
>
<
sf:ConditionalTemplateLeft
=
"DisplayMode"
Operator
=
"Equal"
Right
=
"Read"
runat
=
"server"
>
<
sf:SitefinityLabelid
=
"titleLabel"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"false"
CssClass
=
"sfTxtLbl"
/>
<
sf:SitefinityLabelid
=
"viewControl"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"false"
CssClass
=
"sfRTFContent"
/>
</
sf:ConditionalTemplate
>
<
sf:ConditionalTemplateLeft
=
"DisplayMode"
Operator
=
"Equal"
Right
=
"Write"
runat
=
"server"
>
<
sf:ResourceLinksid
=
"resourcesLinks2"
runat
=
"server"
>
<
sf:EmbeddedResourcePropertySetterName
=
"Telerik.Sitefinity.Resources.Themes.Default.Styles.EditorDialogs.css"
Static
=
"true"
ControlID
=
"editControl"
ControlPropertyName
=
"DialogsCssFile"
/>
<
sf:ResourceFileName
=
"Styles/Window.css"
/>
</
sf:ResourceLinks
>
<
asp:LabelID
=
"titleLabel"
runat
=
"server"
CssClass
=
"sfTxtLbl"
AssociatedControlID
=
"editControl"
/>
<
asp:LinkButtonID
=
"expandLink"
runat
=
"server"
OnClientClick
=
"return false;"
CssClass
=
"sfOptionalExpander"
/>
<
asp:PanelID
=
"expandableTarget"
runat
=
"server"
CssClass
=
"sfEditorWrp sfClearfix"
>
<
telerik:RadEditor
ID
=
"editControl"
runat
=
"server"
Skin
=
"Sitefinity"
Width
=
"100%"
Height
=
"550px"
EnableResize
=
"False"
EditModes
=
"Design,HTML"
DialogHandlerUrl
=
"~/Telerik.Web.UI.DialogHandler.axd"
Content
=
""
NewLineBr
=
"False"
StripFormattingOptions
=
"Css,Font,Span"
OnClientLoad
=
"Telerik$Sitefinity$Web$UI$Fields$HtmlField$radEditorToggleAdvancedToolbars"
OnClientPasteHtml
=
"OnClientPasteHtml"
OnClientCommandExecuting
=
"OnClientCommandExecuting"
>
<
FlashManagerViewPaths
=
"~/Files"
UploadPaths
=
"~/Files"
DeletePaths
=
"~/Files"
/>
</
telerik:RadEditor
>
<
sf:SitefinityLabelid
=
"descriptionLabel"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"true"
CssClass
=
"sfDescription"
/>
<
sf:SitefinityLabelid
=
"exampleLabel"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"true"
CssClass
=
"sfExample"
/>
</
asp:Panel
>
<
scripttype
=
"text/javascript"
>
/*
<![CDATA[ */
var className = null;
var toRemove = false;
var handlersAdded = false;
function OnClientPasteHtml(sender, args)
var newContent = args.get_value();
newContent = newContent.replace(new RegExp("<b(\\s([^>])*?)?>", "ig"), "<strong$1>");
newContent = newContent.replace(new RegExp("</b(\\s([^>])*?)?>", "ig"), "</strong$1>");
newContent = newContent.replace(new RegExp("<i(\\s([^>])*?)?>", "ig"), "<em$1>");
newContent = newContent.replace(new RegExp("</i(\\s([^>])*?)?>", "ig"), "</em$1>");
var regex = /<([a-zA-Z]+) ?[^>]*?>\s*<\/\1>/gi;
newContent = newContent.replace(regex, "");
newContent = newContent.replace(new RegExp("( \s*\n*)+", "ig"), " ");
newContent = newContent.replace(new RegExp("(\s*\n*<br\s*\/?>\s*\n*)+", "ig"), "<br />");
args.set_value(newContent);
function OnClientCommandExecuting(editor, args)
var name = args.get_name();
var val = args.get_value();
className = "re" + args.get_commandName();
if (editor.get_dialogOpener())
if (editor.get_dialogOpener()._container && !handlersAdded)
editor.get_dialogOpener()._container.add_show(AddRemoveCSSClass);
editor.get_dialogOpener()._container.add_close(AddRemoveCSSClass);
handlersAdded = true;
if (name == "MergeTags")
editor.pasteHtml(val);
//Cancel the further execution of the command as such a command does not exist in the editor command list
args.set_cancel(true);
function AddRemoveCSSClass(sender, args)
var popupElement = sender.get_popupElement();
if (!toRemove)
Sys.UI.DomElement.addCssClass(popupElement, className);
else
Sys.UI.DomElement.removeCssClass(popupElement, className);
/* ]]>
*/
</
script
>
</
sf:ConditionalTemplate
>
</
Templates
>
</
sf:ConditionalTemplateContainer
>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
root
>
<
modules
>
<
module
name
=
"RadEditorStatistics"
dockingZone
=
"Bottom"
visible
=
"false"
/>
<
module
name
=
"RadEditorDomInspector"
visible
=
"false"
/>
<
module
name
=
"RadEditorNodeInspector"
visible
=
"false"
/>
<
module
name
=
"RadEditorHtmlInspector"
visible
=
"false"
/>
</
modules
>
<
tools
name
=
"MainToolbar"
>
<
tool
name
=
"ToggleAdvancedToolbars"
/>
<
tool
name
=
"Bold"
shortcut
=
"CTRL+B"
/>
<
tool
name
=
"Italic"
shortcut
=
"CTRL+I"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"InsertOrderedList"
/>
<
tool
name
=
"InsertUnorderedList"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"LinkManager"
shortcut
=
"CTRL+K"
/>
<
tool
name
=
"Unlink"
shortcut
=
"CTRL+SHIFT+K"
/>
<
tool
name
=
"ImageManager"
shortcut
=
"CTRL+G"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"AjaxSpellCheck"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"PasteFromWord"
/>
</
tools
>
<
tools
>
<
tool
separator
=
"true"
/>
<
tool
name
=
"JustifyLeft"
/>
<
tool
name
=
"JustifyRight"
/>
<
tool
name
=
"JustifyCenter"
/>
<
tool
name
=
"JustifyFull"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"Indent"
/>
<
tool
name
=
"Outdent"
/>
</
tools
>
<
tools
>
<
tool
name
=
"FontName"
shortcut
=
"CTRL+SHIFT+F"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"RealFontSize"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"FormatBlock"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"ForeColor"
/>
<
tool
name
=
"BackColor"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"MediaManager"
/>
<
tool
name
=
"FlashManager"
/>
<
tool
name
=
"DocumentManager"
/>
</
tools
>
<
tools
>
<
tool
name
=
"InsertParagraph"
/>
<
tool
name
=
"InsertTable"
/>
<
tool
name
=
"InsertSymbol"
/>
<
tool
name
=
"InsertHorizontalRule"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"Superscript"
/>
<
tool
name
=
"Subscript"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"FormatStripper"
/>
<
tool
separator
=
"true"
/>
<
tool
name
=
"FindAndReplace"
shortcut
=
"CTRL+F"
/>
<
tool
name
=
"Print"
shortcut
=
"CTRL+P"
/>
</
tools
>
</
root
>
Hi Ivan,
How do I do this global mapping that you're referring to?
Thanks!
Devin
I'm also having trouble following this thread. This is a great topic though. As soon as I can wrap my head around this (How to configure RadEditor in Sitefinity), then I'll turn this into a blog post.
I suspect our short-term fix will be a bit complicated though. However, we've also chatted internally about improving this experience. I'm hopeful that all of this can be done through the Configuration UI in future versions.
I'm following this thread with interest and anxious to see the result.
Gabe Sumner
Telerik | Sitefinity CMS
A blog post would be very helpful! We have a custom editor tools file that goes to all of our clients by default.
Thanks,
Devin
Ivan,
refreshUI: function ()
var p = this.get_propertyEditor();
jQuery(p.get_advancedModeButton()).hide();
,
Hello Andrei,
Check whether the get_advancedModeButton()
is not null. It is possible that the value is somehow overridden. Where exactly you use it? From which class your custom control inherits and which is the base of your client component.
Greetings,
Ivan Dimitrov
the Telerik team
Ivan,
Here is the code:
ScottishPanelDesigner.ascx
<%@ Control Language="C#" %>
<%@ Register Assembly="Telerik.Sitefinity" TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" %>
<%@ Register Assembly="Telerik.Web.UI" Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<
telerik:RadWindowManager
ID
=
"windowManager"
runat
=
"server"
Height
=
"100%"
Width
=
"100%"
Behaviors
=
"None"
Skin
=
"Sitefinity"
ShowContentDuringLoad
=
"false"
VisibleStatusBar
=
"false"
>
<
Windows
>
<
telerik:RadWindow
ID
=
"widgetEditorDialog"
runat
=
"server"
Height
=
"100"
Width
=
"100"
ReloadOnShow
=
"true"
Behaviors
=
"Close"
Modal
=
"true"
/>
</
Windows
>
</
telerik:RadWindowManager
>
<
div
>
<
table
>
some values here.....
</
table
>
<
asp:Button
runat
=
"server"
ID
=
"btnClearAll"
OnClientClick
=
"return false;"
CssClass
=
"sfLinkBtnIn"
Text
=
"Clear All "
/>
</
div
>
using System.Linq;
using Telerik.Sitefinity.Web.UI.ControlDesign;
using Telerik.Sitefinity.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Web.UI;
using System.Web.UI;
using System.Collections.Generic;
using System;
namespace SitefinityWebApp.Controls
public class ScottishPanelDesigner : ControlDesignerBase
protected override void InitializeControls(GenericContainer container)
this.DesignerMode = ControlDesignerModes.Simple;
void HtmlControl_PreRender(object sender, EventArgs e)
//hide the Advanced button if not admin.
//this.HideAdvancedMode = true;
//this.DisableAdvancedMode();
private string _layoutTemplatePath = "~/Controls/ScottishPanelDesigner.ascx";
public override string LayoutTemplatePath
get return _layoutTemplatePath;
set _layoutTemplatePath = value;
protected override string LayoutTemplateName
get return "Scotish Panel.";
private const string _layoutTemplateName = "SitefinityWebApp.Controls.ScottishPanelDesigner.ascx";
protected Button ButtonClearAll
get return Container.GetControl<
Button
>("btnClearAll", true);
protected virtual RadWindowManager RadWindowManager
get
return this.Container.GetControl<
RadWindowManager
>("windowManager", true);
private string _scriptPath = "~/Controls/ScottishPanelDesigner.js";
public string DesignerScriptPath
get return _scriptPath;
set _scriptPath = value;
public override IEnumerable<
ScriptReference
> GetScriptReferences()
var scripts = base.GetScriptReferences() as List<
ScriptReference
>;
if (scripts == null) return base.GetScriptReferences();
scripts.Add(new ScriptReference(DesignerScriptPath));
return scripts.ToArray();
public override IEnumerable<
ScriptDescriptor
> GetScriptDescriptors()
var descriptors = new List<
ScriptDescriptor
>(base.GetScriptDescriptors());
var desc = (ScriptControlDescriptor)descriptors.Last();
desc.AddElementProperty("btnClearAll", this.ButtonClearAll.ClientID);
desc.AddComponentProperty("radWindowManager", this.RadWindowManager.ClientID);
return descriptors;
Type.registerNamespace("SitefinityWebApp.Controls");
SitefinityWebApp.Controls.ScottishPanelDesigner = function (element)
SitefinityWebApp.Controls.ScottishPanelDesigner.initializeBase(this, [element]);
this._propertyEditor = null;
this._controlData = null;
this._btnClearAll = null;
this._radWindowManager = null;
this._btnClearAllDelegate = null;
SitefinityWebApp.Controls.ScottishPanelDesigner.prototype =
/* --------------------------------- set up and tear down --------------------------------- */
initialize: function ()
this.refreshUI();
SitefinityWebApp.Controls.ScottishPanelDesigner.callBaseMethod(this, 'initialize');
this._toogleGroupSettingsDelegate = Function.createDelegate(this, function ()
dialogBase.resizeToContent(); );
this._btnClearAllDelegate = Function.createDelegate(this, this._ClearAllTextfields);
$addHandler(this._btnClearAll, "click", this._btnClearAllDelegate);
,
dispose: function ()
SitefinityWebApp.Controls.ScottishPanelDesigner.callBaseMethod(this, 'dispose'); ,
/* --------------------------------- public methods --------------------------------- */
// implementation of IControlDesigner: Forces the control to refersh from the control Data
refreshUI: function ()
var data = this.get_controlData();
//hide the advanced button.
var p = this.get_propertyEditor();
jQuery(p.get_advancedModeButton()).hide();
jQuery("#tbATSIX_60N").val(data.ATSIX_60N);
jQuery("#tbBALIX").val(data.BALIX)
jQuery("#tbBALIX_59N").val(data.BALIX_59N)
jQuery("#tbERAKA").val(data.ERAKA)
jQuery("#tbERAKA_58N").val(data.ERAKA_58N)
jQuery("#tbGOMUP_57N").val(data.GOMUP_57N)
jQuery("#tbRATSU_61N").val(data.RATSU_61N)
jQuery("#tbSCOT_MIL").val(data.SCOT_MIL)
dialogBase.resizeToContent();
,
// implementation of IControlDesigner: forces the designer view to apply the changes on UI to the control Data
applyChanges: function ()
var controlData = this.get_controlData();
controlData.ATSIX_60N = jQuery("#tbATSIX_60N").val();
controlData.BALIX = jQuery("#tbBALIX").val();
controlData.BALIX_59N = jQuery("#tbBALIX_59N").val();
controlData.ERAKA = jQuery("#tbERAKA").val();
controlData.ERAKA_58N = jQuery("#tbERAKA_58N").val();
controlData.GOMUP_57N = jQuery("#tbGOMUP_57N").val();
controlData.RATSU_61N = jQuery("#tbRATSU_61N").val();
controlData.SCOT_MIL = jQuery("#tbSCOT_MIL").val();
,
/* --------------------------------- event handlers --------------------------------- */
_ClearAllTextfields: function ()
var texts = document.getElementsByTagName('input')
for (var i_tem = 0; i_tem < texts.length; i_tem++)
if (texts[i_tem].type == 'text')
texts[i_tem].value = ''
,
/* --------------------------------- properties --------------------------------- */
get_controlData: function ()
return this.get_propertyEditor().get_control();
,
// gets the reference to the propertyEditor control
get_propertyEditor: function ()
return this._propertyEditor;
,
// sets the reference fo the propertyEditor control
set_propertyEditor: function (value)
this._propertyEditor = value;
,
// get the reference to the button that opens page selector
get_btnClearAll: function () return this._btnClearAll; ,
// sets the reference to the button that opens page selector
set_btnClearAll: function (value) this._btnClearAll = value; ,
get_radWindowManager: function () return this._radWindowManager; ,
set_radWindowManager: function (value)
if (this._radWindowManager != value) this._radWindowManager = value;
SitefinityWebApp.Controls.ScottishPanelDesigner.registerClass('SitefinityWebApp.Controls.ScottishPanelDesigner', Sys.UI.Control, Telerik.Sitefinity.Web.UI.ControlDesign.IControlDesigner);
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Hi Andrei,
Your client component registers under IControlDesigner. In this case you need to hide the button as shown below
this
._hideAdvancedDelegate= Function.createDelegate(
this
,
this
._hideAdvanced);
Sys.Application.add_load(Function.createDelegate(
this
,
this
._hideAdvancedDelegate));
...
dispose:
function
()
Sys.Application.remove_load(
this
._hideAdvancedDelegate);
if
(
this
._hideAdvancedDelegate)
delete
this
._hideAdvancedDelegate;
Telerik.Sitefinity.Samples.Web.UI.Designers.ControlDesigner.callBaseMethod(
this
,
'dispose'
);
,
_hideAdvanced:
function
()
jQuery(
this
.get_propertyEditor()._advancedModeButton).hide();
,