Henrik Fransas
Nov 6, 2014
  5985
(0 votes)

How to use TinyMce in a custom property the EPiServer Way–Clean Version

Thanks to feedback from Erik Kärrsgård at EPiServer I learned that I did not need to rewrite all of the code EPiServer has done, it is possible to just extend it. This is great news since it makes it more possible to work even in the future when EPiServer has done some changes to their code.

If you look at the code in my previous post (http://world.episerver.com/Blogs/Henrik-Fransas/Dates/2014/10/how-to-use-tinymce-the-episerver-way-in-a-custom-property/) you can see how the property is build up and the amount of code that I needed to copy. Now the editor descriptor looks like this:

using EPiServer; using EPiServer.Cms.Shell.Extensions; using EPiServer.Core; using EPiServer.ServiceLocation; using EPiServer.Shell.ObjectEditing; using EPiServer.Shell.ObjectEditing.EditorDescriptors; using System; using System.Collections.Generic; namespace TinyMceInCustomProperties.Business.EditorDescriptors { [EditorDescriptorRegistration(TargetType = typeof(XhtmlString), EditorDescriptorBehavior = EditorDescriptorBehavior.ExtendBase, UIHint = Global.SiteUIHints.ExtendedXhtml)] public class ExtendedXhtmlEditorDescriptor : EditorDescriptor { public override void ModifyMetadata(ExtendedMetadata metadata, IEnumerable<Attribute> attributes) { base.ModifyMetadata(metadata, attributes); ExtendedMetadata extendedMetadatum = metadata.FindTopMostContentMetadata(); IContent model; if (extendedMetadatum != null) { model = extendedMetadatum.Model as IContent; } else { model = null; } metadata.ClientEditingClass = "alloy/editors/ExtendedTinyMCEEditor"; metadata.EditorConfiguration.Add("parentValue", ParentValue(model, metadata.PropertyName)); } private string ParentValue(IContent page, string propertyName) { if (page.ParentLink != null) { var repro = ServiceLocator.Current.GetInstance<IContentRepository>(); IContent parent; if (repro.TryGet(page.ParentLink, out parent)) { return ((ContentData)parent).GetPropertyValue(propertyName) ?? string.Empty; } } return string.Empty; } } }

The key thing in this is that I decorate the class with this: EditorDescriptorBehavior = EditorDescriptorBehavior.ExtendBase. This tells EPiServer to use the descriptor for XhtmlString and extend it.

The dojo/javascript files also is a lot smaller with not much duplications of code, the only places is the functions where I need to insert my code. It now looks like this:

define([ // dojo "dojo/_base/declare", // epi "epi-cms/contentediting/editors/TinyMCEEditor", // templates "dojo/text!./templates/ExtendedTinyMCEEditor.html" ], function ( //dojo declare, // epi TinyMCEEditor, // templates template ) { return declare([TinyMCEEditor], { // summary: // Widget for the tinyMCE editor. templateString: template, postCreate: function () { this.inherited(arguments); this.connect(this.inheritButton, "onclick", "onInheritButtonClick"); this.connect(this.inheritFromParentRadioButton, "onclick", "onInheritRadioButtonClick"); this.connect(this.useLocalValueRadioButton, "onclick", "onInheritRadioButtonClick"); this.divParentValue.innerHTML = this._unencodedValue(this.parentValue); }, onInheritButtonClick: function () { var text = this.divParentValue.innerHTML; var ed = this.getEditor(); if (ed && ed.initialized) { ed.setContent(text); } else { this.editorFrame.value = text; } this._onChange(text); }, onInheritRadioButtonClick: function () { var ed = this.getEditor(); if (ed && ed.initialized) { this._onChange(ed.getContent(), true); } }, _setValueAttr: function (newValue) { //summary: // Value's setter // // tags: // protected var ed = this.getEditor(), editableValue = newValue || ""; var isInheritting = editableValue.charAt(0) == "1", editableValue = this._unencodedValue(newValue || ""); if (isInheritting) { this.inheritFromParentRadioButton.checked = true; this.useLocalValueRadioButton.checked = false; } else { this.useLocalValueRadioButton.checked = true; this.inheritFromParentRadioButton.checked = false; } this.inherited(arguments, [editableValue]); }, _onChange: function (val, forcechange) { // summary: // Raised when the editor's content is changed. // // val: // The editor's changed value // // tags: // callback public forcechange = !!forcechange; var hasChanged = this.get("_editorValue") !== val || forcechange === true; if (hasChanged) { this.set("_editorValue", val); val = this._encodedValue(val); this._set("value", val); if (this.validate()) { this.set("_hasPendingChanges", false); this.onChange(val); } } }, _encodedValue: function (orgValue) { var useLocal = this.useLocalValueRadioButton.checked; return (useLocal ? "0:" : "1:") + orgValue; }, _unencodedValue: function (orgValue) { var isSet = orgValue != null && orgValue !== undefined && orgValue.length >= 2 && orgValue.charAt(1) == ":"; return isSet ? orgValue.substring(2) : orgValue; } }); });

The html-template looks the same so look at the previous post to see how it looks like.

The code on github is updated so just clone it at try it out.

The next step is to make this also available in the OnPageEdit mode.

The source code for this you can find here: https://github.com/hesta96/TinyMceInCustomProperties

Thanks again to Erik for his update on the code!

Happy coding!

Nov 06, 2014

Comments

Please login to comment.
Latest blogs
Optimizely Opal: How to Build Effective Workflow Agents

If you're building workflow agents in Optimizely Opal, this post covers how specialized agents pass context to each other, why keeping agents small...

Andre | May 20, 2026

ReviewPR: An Azure Function That Reviews Your Azure DevOps Pull Requests With Claude

A while back I wrote about an  Azure Function App for PDF creation that we use to offload PDF rendering from our Optimizely DXP site. That same...

KennyG | May 19, 2026

Accelerating Optimizely CMS and Commerce upgrades with agentic AI (Part 2 of 2)

The Real Transformation in Optimizely CMS 13: Why the Upgrade Itself Is the Easy Part. A field-tested playbook for enterprise teams moving from...

Hung Le Hoang | May 18, 2026

Is the most powerful AI model really the best value?

Artificial Intelligence is already becoming part of everyday software development. Developers now use AI tools to generate code, write documentatio...

K Khan | May 16, 2026