Sitecore 8: Ribbon Button Transfiguration

Page Editor Ribbon Button

In the old days of Sitecore 6.x and 7.x you might have extended the Content Editor and Page Editor ribbons to give your content editors and marketers an easy access to a great customization of yours. Maybe you built a dialog to expose page metadata. Maybe you built a copy language utility. Maybe you built a workflow wizard of sort. Maybe you built all of the above and more. Whatever the case might be you probably have:

  • An item in the core database. It will be under /sitecore/content/Applications/WebEdit/Ribbons/WebEdit for Page Editor
  • A command name (e.g. mycommands:doasisay registered with a configuration patch to translate to a Command implementation
  • An XML control (a dialog form or a wizard form) that the command will fire up upon a click on the button
  • Code-behind to power the control and interact with the user via Sheer UI

Experience Editor Ribbon Button

Sitecore 8 SPEAK-ified the ribbon. Ribbon buttons for the Experience Editor still live in the core database but they now have … a layout (WAT).

The buttons you’ve built before are there but they don’t show up on the Sitecore 8 ribbon. They are not good enough. They need to step up and transfigure to become a kind of a button that can render itself. They need to be SPEAK-ified.

Transfiguration

We will be SPEAK-ifying a Large Button for this article

Spell One

First, a button needs a new dress. Find your core database item in Sitecore Rocks and add a LargeButton rendering in the layout designer (Ctrl+U)

blog-ribbon-button2

The Experience Editor ribbon is basically a SPEAK page at /sitecore/client/Applications/ExperienceEditor/Ribbon. I suggest you just follow the code from there if you want to see how it’s built and how it works.

This step alone will render your button on the ribbon:

blog-ribbon-button3

Spell Two

Now let’s redress the command. A Sheer UI command has basically three parts to it – a method that determines whether the command should be enabled, a method that triggers the dialog, and a method that acts upon the dialog completion.

Relevant pieces of the old command:

if (args.IsPostBack)
{
    // act upon the dialog completion
    if (args.Result == "yes")
    {
        Context.ClientPage.SendMessage(this, "item:load(...)");
    }
}
else
{
    // trigger the dialog
    UrlString url = new UrlString(UIUtil.GetUri("control:CopyLanguage"));
    url.Add("id", item.ID.ToString());
    url.Add("lang", item.Language.ToString());
    url.Add("ver", item.Version.ToString());

    SheerResponse.ShowModalDialog(url.ToString(), true);

    args.WaitForPostBack();
}

The redressed command (formatted for the blog post):

define(["sitecore"], function (Sitecore) {
    Sitecore.Commands.ScoreLanguageTools = {
        canExecute: function (context) {
            return true; // we will get back to this one
        },
        execute: function (context) {
            var id = context.currentContext.itemId;
            var lang = context.currentContext.language;
            var ver = context.currentContext.version;

            var path = "/sitecore/shell/default.aspx?xmlcontrol=CopyLanguage" +
                       "&id=" + id + "&lang=" + lang + "&ver=" + ver;

            var features = "dialogHeight: 600px;dialogWidth: 500px;";

            Sitecore.ExperienceEditor.Dialogs.showModalDialog(
                path, '', features, null, 
                function (result) {
                    if (result) {
                        window.top.location.reload();
                    }
                }
            );
        }
    };
});

Very similar, isn’t it? Granted, I haven’t SPEAK-ified the dialog itself. Maybe next time.

Spell Three

To make the command accessible at runtime we need to instruct our SPEAK-ified button to load it as its page level script:

blog-ribbon-button4

That’s it. The ribbon button is now fully functional.

Extra

One thing I didn’t cover yet is how to translate the QueryState. My original command was doing something like this:

public override CommandState QueryState(CommandContext context)
{
    Item item = context.Items[0];

    return item.Appearance.ReadOnly ? CommandState.Disabled : CommandState.Enabled;
}

We have two options. We can either do it in JavaScript in canExecute() if we have enough information in the context (we do, it has isReadOnly):

// ...
canExecute: function (context) {
    return !context.currentContext.isReadOnly;
}
// ...

or we can call a processor on the server for help:

// ...
canExecute: function (context) {
    var isEnabled = false;

    Sitecore.ExperienceEditor.PipelinesUtil.generateRequestProcessor(
        "Score.LanguageTools.IsEnabled", 
        function (response) {
            isEnabled = response.responseValue.value;
        }
    ).execute(context);

    return isEnabled;
}
// ...

where Score.LanguageTools.IsEnabled is declared as:

<sitecore.experienceeditor.speak.requests>
    // ...
    <request name="Score.LanguageTools.IsEnabled" 
             type="Score.Custom.LanguageTools.CanExecute, Score.Custom"/>
    // ...
</sitecore.experienceeditor.speak.requests>

and implemented as:

public class CanExecute : PipelineProcessorRequest<ItemContext>
{
    public override PipelineProcessorResponseValue ProcessRequest()
    {
        RequestContext.ValidateContextItem();

        return new PipelineProcessorResponseValue()
        {
           Value = !this.RequestContext.Item.Appearance.ReadOnly
        };
    }
}

Resources

p.s. Is “SPEAK-ified” a word? Maybe it’s “spooky-fied”? Let me know what you think!

Pavel Veller

Add a Comment

Your email address will not be published. Required fields are marked *

Or request call back