8.1 Experience Editor JavaScript APIs

There are parts of Sitecore APIs that are well understood, widely used, and probably won’t change without a really good reason. And then there are relatively new APIs – some introduced along with new product features (e.g. xDB in 7.5, Content Testing in 8.0) and others added to support the shift in the underlying technologies (e.g. SPEAK-ification of the Experience Editor ribbon) . These APIs are young and as they grow and mature they also tend to change their shape and form. This is good news for the APIs – they are getting better indeed – but may surprise a developer maintaining a module for various Sitecore versions.

Sitecore.ExperienceEditor.js

Sitecore 8.0 introduced SPEAK-ified version of the Experience Editor ribbon. If you built or ported your own Page Editor extensions you have probably followed in Sitecore footsteps and used SPEAK pipelines along with Sitecore.ExperienceEditor.js APIs (I know I did). Your code might look like this:

define(["sitecore"], function (Sitecore) {
    Sitecore.Commands.MyNewCommand = {
        canExecute: function (context) {
            return Sitecore.ExperienceEditor.isInMode("edit");
        },

        execute: function (context) {
            context.app.disableButtonClickEvents();

            Sitecore.ExperienceEditor.PipelinesUtil.executePipeline(context.app.MyNewPipeline, function () {
                Sitecore.ExperienceEditor.PipelinesUtil.executeProcessors(Sitecore.Pipelines.MyNewPipeline, context);
            });

            context.app.enableButtonClickEvents();
        }
    };
});

you might also be leaning on a few other helpers:

Sitecore.ExperienceEditor.Dialogs.showModalDialog(...);
...
Sitecore.ExperienceEditor.TranslationsUtils.translateText(...);

These have moved in 8.1. Partly because it had to change (the original Sitecore.ExperienceEditor.js looked as if it was very quickly put together), and partly – I believe – because it’s easier to change a JavaScript API than it is a C# API. Plus, if you don’t document your APIs or otherwise expose implementation teams to its existence you may not feel that you are breaking anything when you’re changing it.

You will see that refactored commands in 8.1 all look similar to this:

define(
  [
    "sitecore",
    "/-/speak/v1/ExperienceEditor/ExperienceEditor.js",
    "/-/speak/v1/ExperienceEditor/TranslationUtil.js"
  ],
function (Sitecore, ExperienceEditor, TranslationUtil) {
  Sitecore.Commands.Lock =
  {
     ...
     ExperienceEditor.PipelinesUtil.executePipeline(...);
     ...
     TranslationUtil.translateText(...);
     ...
  }
});

Sitecore API Wrapper

The refactoring in 8.1 didn’t change the signatures of the methods that I have used – only changed where I would find them. Still, it is a breaking change – my code stopped working. Now I need to fix it and ideally do it and maintain backwards compatibility with 8.0. Here’s what I have quickly come up with. In SitecoreApiWrapper.js:

define(["sitecore"], function (Sitecore) {
    var resolve = function (attr) {
        // ***** Sitecore 8.0 *****
        var result = Sitecore.ExperienceEditor[attr];

        // ***** Sitecore 8.1 *****
        if (!result) {
            result = require("/-/speak/v1/ExperienceEditor/ExperienceEditor.js")[attr];
        }

        return result;
    };

    return {
        PipelinesUtil: function () {
            return resolve("PipelinesUtil");
        },

        Web: function () {
            return resolve("Web");
        },

        Dialogs: function() {
            return resolve("Dialogs");
        },

        TranslationsUtils: function () {
            return Sitecore.ExperienceEditor.TranslationsUtils ||
                   require("/-/speak/v1/ExperienceEditor/TranslationUtil.js");
        }
    };
});

It will basically first try the original namespace and then fall back to requiring a 8.1 module where the things live now. Reflection is very natural with JavaScript where object.property is equivalent to object["property"] and it saved me quite a few keystrokes. I still wish JavaScript had method_missing though.

Here’s how my code looks now:

require.config({
    paths: {
        sitecoreApiWrapper: "/-/speak/v1/mymodule/SitecoreApiWrapper"
    }
});

define(["sitecore", "sitecoreApiWrapper"], function (Sitecore, SitecoreApiWrapper) {
    Sitecore.Commands.MyNewCommand = {
        canExecute: function (context) {
            return context.currentContext.webEditMode === "edit";
        },

        execute: function (context) {
            context.app.disableButtonClickEvents();

            SitecoreApiWrapper.PipelinesUtil().executePipeline(context.app.MyNewPipeline, function () {
                SitecoreApiWrapper.PipelinesUtil().executeProcessors(Sitecore.Pipelines.MyNewPipeline, context);
            });

            context.app.enableButtonClickEvents();
        }
    };
});

The Sitecore.ExperienceEditor.isInMode() was replaced with going after the raw value on the context – this is what both 8.0 and 8.1 do anyway.

I did smile at one change though. TranslationsUtils became TranslationUtil – both words lost the plural vs. singular battle. PipelinesUtil stood its ground.

Pavel Veller

Add a Comment

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

Or request call back