Tuesday, 24 November, 2020

Umbraco - TinyMCE. How to Add the Code Sample plugin for Code Snippet

Umbraco adding Code Snippets to Rich Text Editors.

NOTE: This article is Umbraco 7+ specific, a new post explaining how TinyMCE works on Umbraco 8 will be posted shortly. If you're using Umbraco 7 the good news is the article was recently reviewed and improved.

Preamble

Recently I revamped the website, adding some new features from my wish list, one of which was to improved code sample snippets when inserted code in to posts using Umbraco's built in Rich Text Editor (RTE).

This post explains how to install and use the Code Sample TinyMCE  extension plugin for use with Umbraco's Rich Text Editor control.

Umbraco and TinyMCE

Umbraco 7.10+ uses TinyMCE 4 (https://www.tinymce.com/) to display Rich Text Edit input controls in the back-office.

Editors enter content and the resulting HTML is piped out when someone views the website.

The thing is, it's not configured how you'd expect after reading TinyMCE's documentation. Umbraco has a unique configuration hidden away in it's documentation under https://our.umbraco.org/documentation/reference/config/tinymceconfig/.

Umbraco ships TinyMCE with what appears to be a full set of plugins; you can find them under \Umbraco\lib\tinymce\plugins - but not all of them are configured for use.

Not all TinyMce features are enabled by default in Umbraco, you can use this configuration file to enable other TinyMce plugins or ammend the core behaviour of the Rich Text Editor in Umbraco. Umbraco Documentation.

There are plugins to perform spellchecking, word counts and printing Etc.

The Code Sample Plugin

The plugin we're going to use is called Code Sample, read the TinyMCE documentation at: https://www.tinymce.com/docs/plugins/codesample/.

"The Code Sample plugin (codesample) lets a user insert and embed syntax color highlighted code snippets into the editable area. It also adds a button to the toolbar which on click will open a dialog box to accept raw code input." TinyMCE Website

Code Sample produces code snippets like below.

public ActionResult Index(RenderModel model)
{
    return Content("Error:Contact Surface Controller index not found.");
}

Note: When adding a code snippet using the Code Sample plugin with Umbraco's RTE you need to click the Code Sample button and then add the code and select the language; if you try to highlight code after you've pasted it in to the RTE control Code Sample will not work.

Prism.js

In turn, the Code Sample plugin is built on Prism.js (http://prismjs.com/), which is bundled inside Code Sample and shipped with TinyMCE inside Umbraco.

"Prism is a lightweight, extensible syntax highlighter, built with modern web standards in mind. It’s used in thousands of websites, including some of those you visit daily" Prism Website

Once configured the CodeSample and Prism.js will display your snippets perfectly formatted inside you Rich Editor control but not on your website front-end which is why I mention it here.

Configuring Umbraco

We're going to add a new button to the Umbraco Rich Text Editor toolbar to apply code samples.

First open the \config\tinyMceConfig.config  XML file and find the <commands> section.

Next add a new command section.

For Umbraco 7 this achieved as shown in the example below:

<commands>
    ...
    <command>
      <umbracoAlias>codesample</umbracoAlias>
      <name>Code Sample</name>
      <icon>notused</icon>
      <tinyMceCommand value="" userInterface="true" frontendCommand="codesample">codesample</tinyMceCommand>
      <priority>75</priority>
    </command>
</commands>
umbracoAlias defines a unique alias within Umbraco for the command. This alias should not contain any spaces.

icon 
defines the path to an image file to be used on the formatting toolbar. This image should be 16px x 16px in size.

tinyMceCommand 
defines the tinyMceCommand properties.To further break this down, the value attribute is usually an empty value as most commands perform formatting tasks as opposed to returning values. The userInterface attribute takes a boolean value indicating whether or not the command has an additional UI component to display e.g. a new dialog to assist with inserting images. frontendCommand defines the name of the command to execute. This value usually matches the value of the tinyMceCommand node.

priority 
defines the sort order for the commands and should be sequentially incremented for each new command.

Umbraco Documentation

Note the priority setting values must be in sequential order, so if the last value was 123 the next section's value should be 124+. If you need to move the button elsewhere on the toolbar you reorder the priority setting values.

Next, add the CodeSample plugin to the list of plugins as shown below:

  <plugins>
    <plugin loadOnFrontend="true">code</plugin>
    <plugin loadOnFrontend="true">codemirror</plugin>
    <plugin loadOnFrontend="true">paste</plugin>
    <plugin loadOnFrontend="true">anchor</plugin>
    <plugin loadOnFrontend="true">charmap</plugin>
    <plugin loadOnFrontend="true">table</plugin>
    <plugin loadOnFrontend="true">lists</plugin>
    <plugin loadOnFrontend="true">hr</plugin>
    <plugin loadOnFrontend="true">codesample</plugin>
  </plugins>

Where's the Button?

The Code Sample button still won't show up in the RTE toolbar until you add it.

To do this go to Dev > Data Types and select the Rich Text Editor Data Type.

This is where you add and remove TinyMCE supported plugins to Umbraco's default RTE enabling editors to see them. Browse down the list of plugins, find Code Sample and tick it.

If you can't see Code Sample in the list try restarting Umbraco, either by refreshing the application pool or forcing an update by editing the web.config file, afterwards it should appear. 

Now if you save your file and restart the web app the button will be there, and will work for the back-office, but won't have an icon yet. We'll add that next.

Adding A Toolbar Icon

The TinyMCE font used to display icons in the toolbar can be found under <yourprojectdir>\Umbraco\lib\tinymce\skins\umbraco\fonts. To view the icons available you'll need to load the font in to a font editor, the easiest way I found was to install the .ttf font on to Windows and open it with Charmap. Icon 0xE603 looked good to me so I chose that.

Create CSS to display the icon. You'll need to modify the TinyMCE lib installed with Umbraco under <yourprojectdir>\Umbraco\lib\tinymce\skins\umbraco\skin.min.css and

add the following:

i.mce-ico.mce-i-codesample:before {
    content: "\e603";
}

This should match the name of your command.

Refresh the web app and you'll see the icon. The back-office should now let you add code samples but the styling may be bit off.

Fix Backoffice Styling

If the Umbraco RTE isn't set-up to allow <code> elements it'll strip them out when you save the code snippet and break the styling. If your noticing problems open the TinyMCEConfig.config again and check the <ValidElements> note includes an entry for code. See the example below for how to tack codeon to the end of the list of allowed elements.
  <validElements>
    <![CDATA[+a[id|style|rel|data-id|data-udi|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|
ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],
-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],
img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],
-sub[style|class],-sup[style|class],-blockquote[dir|style|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],
-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],
thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],
-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],
-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],
-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],
dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],
param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*],code]]>
  </validElements>
The validElements node defines which elements will remain in the edited text when the TinyMce Rich Text Editor (RTE) saves. You can use this to limit the returned HTML to a subset.

Umbraco Documentation

If you'd like to know a little more about how these valid elements are configured checkout https://www.tinymce.com/docs/configure/content-filtering/#valid_elements.

The Front-end

At the moment the front-end doesn't now how to display the code snippet. It'll wrap it in <pre><code> but won't provide any Prism styling or language highlighting.

To Highlight the code we need to download the Prism.js and Prism.css files from http://prismjs.com/download.html where you can select a desired theme, language support and any additional plugins. I chose to add the Highlight Keyword plugin and support for ASP.NET (C#) to the standard defaults.

Once you've downloaded the files, added and included them to your project the code samples will start displaying properly on the frontend.

<link href="prism.css" rel="stylesheet">
<script src="prism.js"></script>

Highlighting

You'll notice highlighting just works.

Yet if you read the Prism Highlight documentation http://prismjs.com/plugins/highlight-keywords/  it indicates you need to include some JavaScript. The reason it works is that you ticked the Highlight Keyword plugin when you created the Prism download bundle and so it was automatically added to the Prism.js downloaded.

If you find yourself wanting more control over when and how plugin JavaScript is downloaded you can always download the core Prism.js components and link to the plugin JS when and if you need it.

(function(){

if (
	typeof self !== 'undefined' && !self.Prism ||
	typeof global !== 'undefined' && !global.Prism
) {
	return;
}

Prism.hooks.add('wrap', function(env) {
	if (env.type !== "keyword") {
		return;
	}
	env.classes.push('keyword-' + env.content);
});

})();

Trouble-Shooting

It doesn't work:
When adding a code snippet you need to click the Code Sample icon on the RTE toolbar then add the code and then select the language; if add the code and then try to highlight it after you've pasted it it won't work.

The code isn't highlighted:
If the code is formatted but not highlighted you made have missed the Fix BackOffice Styling step above. Make sure you've included the code element in your list of valid elements for TinyMCE. Note that you'll have to republish your content to save the HTML without the code element stripped out.

That's A Wrap

We've talked about Umbraco RTE property editors, how they're implemented using TinyMCE and how Umbraco configures TinyMCE.

We added a new icon to the Umbraco RTE toolbar and discussed how to extend Umbraco RTE to include support for code snippets, and how to display code using Prism.

Happy coding.

Want to Thank Me?

Did you like this article? Was it helpful? Why not buy me a coffee on PayPal? Buy me a coffee?