Sitecore Insiders

Code Editor for custom field using SPEAK & CodeMirror – Part 1

Part 1 – Create a dialog using SPEAK components

Most of the times, in development, things that have a name sounds complicated, the unknown psychological fear, especially when you feel that you won’t have enough time to investigate something that can lead you to hours of troubleshooting. Here you will learn how to create a dialog using SPEAK components easily.

If you never work with SPEAK before, let me tell you that we will just create some items, add some renderings, add code to model it and voi lá. If you did already, you know that we are just going to create some items, add some renderings, add code to model it and voi lá.

To do this you will need Visual Studio and Sitecore Rocks. This is the best way and the one recommended by Sitecore. For simple things like change some parameters in a duplicated component you can live without Sitecore Rocks, but if you are going to create something new, you should use it.

Defining layout

  • Open Sitecore Explorer in Sitecore Rocks, open Core database and go to /sitecore/client/Applications/Dialogs
  • Here you have some default dialogs and I based this creation in InsertAnchorDialog. It is “simple” and have a dialog, a title, a label, a Textbox and action buttons. We will do something different of it in terms of layout, but this guided me on what to fulfill in each component.
  • Start by creating a new item under Dialogs folder, choose the template “Speak-DialogPage” and name it “CodeEditor”. Change the BrowserTitle to “Code Editor”.
  • This is the page where components will live, and to add them, go to Design Layout by right-click, Tasks, Design Layout.
  • Set the layout field as /sitecore/client/Speak/Layouts/Layouts/Speak-Layout
  • The idea is to have a header with a title, a label and a Textarea in the body with Save & Cancel buttons in the footer.
  • Here renderings work like Sitecore Renderings, some generate placeholders others just have behavior. Each rendering can be configured in VS Properties panel.

Adding Renderings

  • Start adding the following renderings, choosing always Speak version 1 renderings.
    • Add the Dialog rendering and make sure it is mapped to Page.Body placeholder. If not, double-click the rendering or right-click & Edit to open Properties panel, then change placeholder field.
    • Add a DialogHeader
      • PlaceholderKey: DialogHeader
    • Add a Text
      • ID: “Title”
      • Text: “Code Editor”
      • PlaceholderKey: DialogHeader.Title
    • Add a Text
      • ID: “CodeTextLabel”
      • Text: “Code”
      • PlaceholderKey: DialogContent
    • Add a Textarea
      • ID: “CodeText”
      • PlaceholderKey: DialogContent
    • Add a DialogFooter
      • PlaceholderKey: DialogFooter
    • Add a Button
      • ButtonType: “Primary” to make it a Sitecore blue button
      • Click: “javascript:app.save()” so it will call a save method in the JS page code that you will create
      • ID: “SaveButton”
      • Text: “Save”
      • PlaceholderKey: DialogFooter.Buttons
    • Add a Button
      • ID: “CancelButton”
      • Text: “Cancel”
      • PlaceholderKey: DialogFooter.Buttons
    • Add PageCode
      • PlaceholderKey: “Page.Code”
      • for now this is just to allow you to preview it correctly, we will return here.
    • Save All.
  • You can preview it by opening https://yourinstanceurl/sitecore/client/Applications/Dialogs/CodeEditor.

Behavior through Rules

Now let’s give it a bit of behavior, we have Save and Cancel buttons that can be put to work just by adding Rule renderings.
With Rule renderings you can add basic behavior to controls without coding, otherwise you will have to do it in C# or JS by yourself since this will generate JS code automatically.

  • Before adding the Rule rendering for “Save” button, it’s necessary to create a datasource item for it.
    • Go to your CodeEditor dialog item and right-click, add, PageSettings, keep PageSettings name.
    • Add a RuleDefinition item under PageSettings, call it “SaveRuleDefinition”. Don’t forget to always check for version 1 reference in the path of the template.
    • Open the item and just edit the rule
    • Add the “where always” condition
    • Add the “set the dialog return value to component name propertyName” action and set “name” value to “CodeText” and “propertyName” to “Text”.
      The name is your input ID and the properyName represent the value property of the input.
    • Add the “close the dialog” action and close the editor.
    • In the top of the item editor you have the item info, like Item Name, Item ID, Item Path, etc. Copy the Item ID to paste it next on Rule rendering.
  • To map this rule definition, return to CodeEditor Layout Design and
    • Add a Rule rendering
      • ID: “SaveRule”
      • PlaceholderKey: “Page.Body”
      • RuleItemId: paste the RuleDefinition item id
      • TargetControl: “SaveButton” to map it to save button
      • Trigger: “click”
  • For the Cancel button we repeat the process, create RuleDefinition item under PageSettings
    • Call it CancelRuleDefinition
    • Add the “where always” condition and the “close the dialog” action
    • Copy the ItemId
  • Return to Layout Design
    • Add a Rule rendering for Cancel button
      • ID: “CancelRule”
      • PlaceholderKey: “Page.Body”
      • RuleItemId: paste the RuleDefinition item id
      • TargetControl: “CancelButton” to map it to cancel button
      • Trigger: “click”

Result

List of renderings in SPEAK Dialog
Image 1 – SPEAK Dialog renderings

Creating the PageCode

I couldn’t find documentation about it, but I can tell you by trial and error that, in order to make this dialog work with the custom field type, it’s necessary to have a C# page code and, since we will add a JS plugin to this editor, we need a JS page code as well. In official documentation this is a referred as an “OR” and not as an AND/OR.

C# Code Page

  • Create a C# class called CodeEditorPageCode inheriting from PageCodeBase
  • Add a property of type Sitecore.Mvc.Presentation.Rendering with the same name as Textarea ID that you add to the dialog, in this case, “CodeText”.
  • Then implement Initialize method to initialize property value, as shown on the code below. When calling the dialog, we are going to pass the value from custom field instance through the UrlHandler class. Curious about this “session values helper” class? Read this https://sitecorejunkie.com/2012/11/09/get-a-handle-on-urlhandle/.
using Sitecore.Web;
using Sitecore.Web.PageCodes;
namespace SitecoreInsiders.Shell.CodeEditor.Controls
{
    public class CodeEditorPageCode : PageCodeBase
    {
        public Sitecore.Mvc.Presentation.Rendering CodeText { get; set; }

        public override void Initialize()
        {
            //get UrlHandle aka Session values helper
            UrlHandle urlHandle;
            UrlHandle.TryGetHandle(out urlHandle);
           //when previewing the dialog this handle will be null
            if (urlHandle == null)
                return;
            var codeText = urlHandle["CodeText"];
            this.CodeText.Parameters["Text"] = codeText;
        }
    }
}
  • Go to CodeEditor Design Layout, go to PageCode properties and set “PageCodeTypeName” to “namespace.classname, assemblyName”, like this “SitecoreInsiders.Shell.CodeEditor.Controls.CodeEditorPageCode,SitecoreInsiders.Shell.CodeEditor”.

JavaScript Code Page

  • Now create folders in your solution to have a JS file in the path “sitecore\shell\Applications\Dialogs\CodeEditor”. Create a JS file called CodeEditor.js
  • This file will be where you define the fancy code to do genious things inside the dialog. The base code before the fancy is:
define(["sitecore"], function (Sitecore) {
  var CodeEditor = Sitecore.Definitions.App.extend({
    save: function(){
	if(!this.CodeText.get('text').trim())
	    this.CodeText.set('text', "__#!$No value$!#__");
        console.log(‘What a save!’)
    },
    initialized: function () {
    }
  });
  return CodeEditor;
});
  • Go back to CodeEditor Design Layout, go to PageCode properties and set “PageCodeScriptFileName” to “relativePath/filename.js”, like this “/sitecore/shell/Applications/Dialogs/CodeEditor/CodeEditor.js”.

You can preview it again and make sure that no errors are in console, which means you did everything right, otherwise, it was me or you doing something wrong. Until now, everything is well connected, no sorcery-at-first-sight.

In the next chapter we are going to create the custom field. Click here to go to the next step.

Bruno Nunes

Sitecore developer since 2015, passed by 7.5, 8.2, 9.1, next step will be the 10!
Self-motivated to bring new capabilities to Sitecore and to adapt it for every business case.
Currently working on Noesis as Sitecore Architect / Tech Lead.

Add comment

Bruno Nunes

Sitecore developer since 2015, passed by 7.5, 8.2, 9.1, next step will be the 10!
Self-motivated to bring new capabilities to Sitecore and to adapt it for every business case.
Currently working on Noesis as Sitecore Architect / Tech Lead.