Sitecore Insiders

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

Part 3 – Add a field menu button to open the dialog

In the 1st part we created the dialog then on the 2nd we created the custom field type, now it’s time to apply the glue between them, the menu button.

It is very simple to add the button and very simple to open the dialog, the tricky part was to understand what was necessary to transport the value and behind this simplicity there was hours of research. I can tell you that I brought many inspirations to the C# code file in ways of having 3+ times the rows you will see and then, after understanding each piece of the code, I’m giving you this simple and light piece of code.

Btw, check here the previous step.

Adding a menu button

We want a button on top of the control like Rich Text has in order to call a dialog. To do this, you will need a folder under the custom field type and an item to define the button.

  • Switch to Core database
  • Let’s peek “Rich Text” in /sitecore/system/Field types/Simple Types/Rich Text/Menu/Edit Html and check how it’s done.
    This the Edit Html button that you see on Rich Text field, when clicking it open as dialog with the Rich Text Editor, and we want something like that.
  • Go to /sitecore/system/Field types/Custom Types/Code and create a subitem called Menu with the template “/sitecore/templates/Common/Folder”
  • Create the menu button inside that folder using the template “/sitecore/templates/System/Menus/Menu item” and call it “Code Editor”.
  • Here you will have to define the “Display Name” and the “Message”.
    First one it’s what will be displayed as the button label, set it as “Edit in Code Editor”.
    The second is to define the event message when you click the button. This value will be handled inside the field class and, according to it, you will decide what to do or what dialog to invoke for example. In this case set it as “codefield:editcode(id=$Target)”. This $Target seems to be the current item field id so it can grab the value in it.
  • Done, your menu button is defined.

Handling menu button click

The button is created, now we need to map his action, or more precisely, we need to map his message.

  • Return to Visual Studio and to the class CodeField
  • Override the HandleMessage method. This will handle the click action and, according to the message passed by the click, do something. In this case, it is going to call OpenEditor method that I will explain right after.
public override void HandleMessage(Message message)
{
	Assert.ArgumentNotNull(message, "message");
	base.HandleMessage(message);

	if (message["id"] != ID)
		return;

	switch (message.Name)
	{
		//message defined in Menu item
		case "codefield:editcode":
			OpenEditor();
			break;

		default:
			return;
	}
}

protected void OpenEditor()
{
	Sitecore.Context.ClientPage.Start((object)this, "EditCode");
}

Calling the dialog

Here is where things start to happening, things that you do and you just believe that will make it happen. I followed the “recipe.peek” and reach this simple code.
We need a method to be called by a pipeline, and this method will execute what you want and support post back.

As I told you in the dialog C# PageCode, we use UrlHandle, aka Session values helper, to pass the current field value, and it’s here where we pass it. The url of the dialog will be the key of the group of values and we are storing the field value in the “CodeText”. Basically it’s a Session value holding a collection.

Then we call the SheerResponse.ShowModalDialog with some options and, most important, the URL of our dialog previously defined. I didn’t research about Sheer and what can we do with it, but, as far as I understood on diagonal readings, we could skip SPEAK part and build a dialog using XML.

Enough talking, this is the code:

/// <summary>Opens the Code Editor dialog or handles dialog result.</summary>
/// <param name="args">The args.</param>
protected void EditCode(ClientPipelineArgs args)
{
	Assert.ArgumentNotNull((object)args, nameof(args));
	if (this.Disabled)
		return;

	if (args.IsPostBack)
	{
		//cancel button will return "undefined"
		if (string.IsNullOrEmpty(args.Result) || args.Result == "undefined")
			return;

		var text = string.Empty;
		//because empty text value will always return "undefined", 
		//when we want to clear the value in the editor, we set it as this string.
		if (args.Result != "__#!$No value$!#__")                    
		{
			text = args.Result;
		}

		if (text != this.Value)
		{
			this.Value = text;
			this.SetModified();
		}
		Sitecore.Context.ClientPage.ClientResponse.SetAttribute(this.ID, "value", this.Value);
	}
	else
	{
		UrlString urlString = new UrlString("/sitecore/client/Applications/Dialogs/CodeEditor");
		UrlHandle urlHandle = new UrlHandle();
		urlHandle["CodeText"] = this.Value;
		urlHandle.Add(urlString);
		ModalDialogOptions options = new ModalDialogOptions(urlString.ToString())
		{
			Width = "1000",
			Height = "600",
			Response = true
		};
		SheerResponse.ShowModalDialog(options);
		args.WaitForPostBack();
	}
}

This is the code to call the dialog and to handle the response but who executes this code is a pipeline called in the OpenEditor method. We pass this class instance to the pipeline and indicate that it should execute the method EditCode. (this code was already referenced in the topic before)

protected void OpenEditor()
{
	Sitecore.Context.ClientPage.Start((object)this, "EditCode");
}

Finally you can open your dialog through the custom field type! Next chapters will be about the CodeMirror and JS PageCode file. Click here to go to the next step.

Source Code

Still in doubt with something? Check here. Have in mind that this is the final product.

https://github.com/sitecoreinsiders/SitecoreRepo/blob/v1.0/SitecoreInsiders.Shell.CodeEditor/Controls/CodeField.cs

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.