[su_note note_color=”#fafafa”]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.[/su_note]
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 toobject["property"]
and it saved me quite a few keystrokes. I still wish JavaScript hadmethod_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 thecontext
– this is what both 8.0 and 8.1 do anyway.[su_divider][divider top=”1″][/su_divider]
I did smile at one change though.
TranslationsUtils
becameTranslationUtil
– both words lost the plural vs. singular battle.PipelinesUtil
stood its ground.