The RichText field in Magnolia is a custom field used in Magnolia apps that makes use of CKEditor, a popular open source web text editor. It is used for creating enriched content containing elements other than plain text like images, lists, tables or formatted source code snippets. Out of the box the Magnolia RichText field already provides some common options that are easy to adjust by setting properties in the JCR configuration or in a YAML configuration file.

Examples for such options are lists or table that you can just turn on or off by setting true or false in the configuration.

Extending basic configuration options

CKEditor itself is a complex tool that has plenty of options and also a variety of plugins that can be integrated.

In this tutorial I’ll show you how to:

  • replace the default CKEditor configuration provided with Magnolia
  • change the default behavior of the CKEditor in a RichText field
  • add a plugin to the CKEditor configuration
  • configure the plugin
  • edit content with the new features and make use of edited content in templates

To be able to edit HTML syntax in the RichText field in a convenient way, we use use CodeMirror plugin to extend the existing CKEditor configuration provided with Magnolia. Of course you can use this tutorial also to integrate other plugins and tools for CKeditor in a similar fashion (the Magnolia documentation is quite limited on this topic).

Integrate the plugin

First we copy the contents of the CodeMirror plugin to our Magnolia module using the path

src/main/resources/VAADIN/js/codemirror

Make use of your custom RichText configuration

The Magnolia RichText provides the configJsFile configuration option where you can overwrite the default configuration file included with Magnolia. Example how this can be done in the JCR configuration:

You can see that we also enable the source button in the RichText field.

For comparison you can find the original configuration file used by Magnolia in the Git repository.

For our modified RichText field, we provide this configuration file:

CKEDITOR.plugins.addExternal("codemirror", CKEDITOR.vaadinDirUrl + "js/codemirror/");

CKEDITOR.editorConfig = function( config ) {
  // MIRROR info.magnolia.ui.form.field.definition.RichTextFieldDefinition
  definition = {
    alignment: false,
    images: true,
    lists: true,
    source: true,
    tables: true,
	colors: null,
	fonts: null,
	fontSizes: null
  }
  // MIRROR info.magnolia.ui.form.field.factory.RichTextFieldFactory
  removePlugins = [];

  // CONFIGURATION FROM DEFINITION
  if (!definition.alignment) {
    removePlugins.push("justify");
  }
  if (!definition.images) {
    removePlugins.push("image");
  }
  if (!definition.lists) {
    // In CKEditor 4.1.1 enterkey depends on indent which itself depends on list
    removePlugins.push("enterkey");
    removePlugins.push("indent");
    removePlugins.push("list");
  }
  if (!definition.source) {
    removePlugins.push("sourcearea");
  }
  if (!definition.tables) {
    removePlugins.push("table");
    removePlugins.push("tabletools");
  }
  if (definition.colors != null) {
    config.colorButton_colors = definition.colors;
	config.colorButton_enableMore = false;
    removePlugins.push("colordialog");
  } else {
    removePlugins.push("colorbutton");
    removePlugins.push("colordialog");
  }
  if (definition.fonts != null) {
    config.font_names = definition.fonts;
  } else {
    config.removeButtons = "Font";
  }
  if (definition.fontSizes != null) {
    config.fontSize_sizes = definition.fontSizes;
  } else {
    config.removeButtons = "FontSize";
  }
  if (definition.fonts == null && definition.fontSizes == null) {
    removePlugins.push("font");
    removePlugins.push("fontSize");
  }

  // DEFAULT CONFIGURATION FROM FIELD FACTORY
  removePlugins.push("elementspath");
  removePlugins.push("filebrowser");
  config.removePlugins = removePlugins.join(",");
  config.extraPlugins = "magnolialink,magnoliaFileBrowser,codemirror";
 
  //CODEMIRROR PLUGIN CONFIGURATION
  config.codemirror = {
    theme: 'default',
    lineNumbers: true,
    lineWrapping: true,
    matchBrackets: true,
    autoCloseTags: true,
    autoCloseBrackets: true,
    enableSearchTools: true,        // Whether or not to enable search tools, CTRL+F (Find), CTRL+SHIFT+F (Replace), CTRL+SHIFT+R (Replace All), CTRL+G (Find Next), CTRL+SHIFT+G (Find Previous)
    enableCodeFolding: true,        // Whether or not you wish to enable code folding (requires 'lineNumbers' to be set to 'true')
    enableCodeFormatting: false,
    autoFormatOnStart: false,        // Whether or not to automatically format code should be done when the editor is loaded
    autoFormatOnModeChange: false,   // Whether or not to automatically format code should be done every time the source view is opened
    autoFormatOnUncomment: false,    // Whether or not to automatically format code which has just been uncommented
    mode: 'htmlmixed',              // Define the language specific mode 'htmlmixed' for html including (css, xml, javascript), 'application/x-httpd-php' for php mode including html, or 'text/javascript' for using java script only
    showSearchButton: true,         // Whether or not to show the search Code button on the toolbar
    showTrailingSpace: true,
    highlightMatches: true,
    showFormatButton: true,
    showCommentButton: true,
    showUncommentButton: true,
    showAutoCompleteButton: true,
    styleActiveLine: true
  };

  config.baseFloatZIndex = 150;
  config.resize_enabled = false;
  config.toolbar = "Magnolia";
  config.toolbar_Magnolia = [
    { name: "basicstyles",   items: [ "Bold", "Italic", "Underline", "SpecialChar" ] },
    { name: "paragraph",     items: [ "NumberedList", "BulletedList", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock", "Image", "Table" ] },
    { name: "links",         items: [ "Link", "InternalLink", "DamLink", "Unlink" ] },
    { name: "styles",        items: [ "Font", "FontSize", "TextColor" ] },
    { name: "clipboard",     items: [ "Cut", "Copy", "Paste", "PasteText", "PasteFromWord" ] },
    { name: "undo",          items: [ "Undo", "Redo" ] },
    { name: "tools",         items: [ "Source" ] }
  ];

  config.allowedContent = true; // don't filter my data
  config.entities_processNumerical = false;
  config.fillEmptyBlocks = false; // no &nbsp; in <p>
  config.autoParagraph = false;
};

You can see that we added the CodeMirror plugin

CKEDITOR.plugins.addExternal("codemirror", CKEDITOR.vaadinDirUrl + "js/codemirror/");

and also configuration options provided by the plugin itself.

If everything went well and the module is integrated in your Magnolia web application, you will have a nicely formatted source view - Quellcode in German - in your RichText editor:

Make use of syntax formatting on the front end

In your enhanced RichText editor you now can switch to the source view and enclose source code in pre HTML tags, which will be used to format the code in HTML templates later.

In addition to that, we will include the Google Javascript code prettifier to be able to display nicely formatted source code on our web pages without the need to write our own custom CSS.

So in your template header include the script like this

<!-- Google Pretty Print -->
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

and then mark source code in the RichText editor like

As a result, your web pages can display source code like the example below:

This is a much nicer result than just using a fixed font or no formatting at all for source code snippets!

Notes

You can do the same if you use YAML for Magnolia apps, just just have to provide the options as shown above in your YAML text file.

Resources