HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideLegal TermsGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

Context-sensitive components

Describes context-sensitive components in the Optimizely Content Management System (CMS) user interface.

Optimizely Content Management System (CMS) supports context-sensitive client components. Context could be the current page that the user is working with. Because CMS loosely couples components, the context service object handles the current context. To get hold of the current context, you could do this:

var contextService = dependency.resolve("epi.shell.ContextService");
var currentContext = contextService.currentContext;

The context service on the client interacts with the server to resolve context for the selected page, block, or entity. The actual properties on the context object depend on the type of context displaying, but a few properties are available for all contexts:

PropertyDescription
uriThe key that uniquely identifies the entity in context.
previewUrlThe URL on which you can display the entity in the editing UI.
data  The values of the entity in context.
type The type of data for this context, derived from the URI.
id The ID of the data for this context, derived from the URI.

Context on the server implements the IClientContext interface and is serialized to the client.

Example: epi.cms.contentdata Context

{
      "parentLink"         : "4",
      "customViewType"     : "",
      "language"           : "en",
      "publicUrl"          : "/MaintAlloy/Alloy-Track/",
      "capabilities"       :
                             {
                               "languageSettings"  : true,
                               "securable"         : true,
                               "dynamicProperties" : true,
                               "isFolder"          : false,
                               "isPage"            : true,
                               "contentResources"  : true,
                               "language"          : true,
                               "isBlock"           : false
                             },
      "languageContext"    :
                             {
                               "isTranslationNeeded"          : false,
                               "language"                     : "en",
                               "isPreferredLanguageAvailable" : true,
                               "preferredLanguage"            : "en",
                               "reason"                       : 1,
                               "warning"                      : null,
                               "hasTranslationAccess"         : true
                             },
      "hasSiteChanged"     : false,
      "fullHomeUrl"        : "http://localhost/MaintAlloy/EPiServer/CMS/Home",
      "versionedUrl"       : "",
      "dataType"           : "epi.cms.page",
      "uri"                : "epi.cms.contentdata:///8_8",
      "previewUrl"         : "/MaintAlloy/EPiServer/CMS/Alloy-Track,,8_8/?id=8_8&epieditmode=true",
      "data"               : null,
      "name"               : "Alloy Track",
      "requestedUri"       : "epi.cms.contentdata:///8",
      "versionAgnosticUri" : "epi.cms.contentdata:///8"
    }

The ContentDataContext class is serialized to produce this client context.

Access context in components with _ContextMixin

To simplify interaction with the context, you can implement a mix-in that provides access to the context from a component.

define(["dojo/_base/declare", "dojo/when", "epi/shell/_ContextMixin"],
    function (declare, when, _ContextMixin) {
      return declare([_ContextMixin], {
          constructor: function () {
            when(this.getCurrentContext(), function (context) {
              console.log("we have context: ", context);
            });
          }
        }
      });

The _ContextMixin extends the class with the following methods:

MethodDescription
getCurrentContext()Returns an available context or a deferred object that resolves to the context when it is available.
currentContextThe currently loaded context, which may be null.
contextChanged(context, callerData) Calls an overridable method when the context changes. Components should check that the context is not null and may look at context.type to determine whether they can work with a given context.
contextChangeFailed(previousContext, callerData) Calls an overridable method when loading the context fails for any reason.

Change the current context

If you need to change the current context, publish a message to the /epi/shell/context/request channel with parameters for the new context as the data. A URI parameter property is required to determine which type of context to load. The following example changes the current context to a CMS ContentData object:

var pageLink = "5_135"; //Replace with code to determine the pageLink for the page you want to change to..
var contextParameters = { uri: 'epi.cms.contentdata:///' + pageLink };
topic.publish("/epi/shell/context/request", [contextParameters]);

Listen to changes to the current context using a subscription

Without using _ContextMixin, you can subscribe to context changes using the dojo pub/sub infrastructure. If you want to react to a context change, subscribe to the/epi/shell/context/changed message:

startup: function () {
    this.subscribe("/epi/shell/context/changed", this._contextChanged);
  },
  _contextChanged: function (newContext) {
    if (!newContext) {
      return;
    }
    //Do something with newContext.
  }

Implement a context resolver on the server

To provide context for certain entities, you can implement the following context resolver interfaces.

  • Resolve a known reference using URI
  • Query context on a specific URL

The following example shows a context resolver that performs both these tasks:

/// Resolves URIs and URLs to files for the shell context service.
[ServiceConfiguration(typeof (IUrlContextResolver))]
[ServiceConfiguration(typeof (IUriContextResolver))]
public class CmsFileContextResolver: IUriContextResolver, IUrlContextResolver {
  private VirtualPathProvider _vpp;

  public CmsFileContextResolver(VirtualPathProvider vpp) {
    SortOrder = 123;
    _vpp = vpp;
  }

  /// The name of the model the context contextualizes.
  public string Name {
    get {
      return "epi.cms.unifiedfile";
    }
  }

  /// Resolves a page link in URI format.
  public bool TryResolveUri(Uri uri, out IClientContext instance) {
    instance = ResolvePath("~" + uri.LocalPath);
    return instance != null;
  }

  /// Tries to resolve an url to page context.
  public bool TryResolveUrl(Uri url, out IClientContext instance) {
    instance = ResolvePath(url.LocalPath);
    return instance != null;
  }

  private IClientContext ResolvePath(string path) {
    var file = _vpp.GetFile(path) as UnifiedFile;
    if (file == null) {
      return null;
    }
    return new Models.UnifiedFileContext {
      Uri = new Uri("epi.file.unifiedfile://" + VirtualPathUtilityEx.ToAppRelative(file.VirtualPath).TrimStart('~')),
        Data = new {
          file.VirtualPath,
            // ... more unifiedfile-specific data
        },
        PreviewUrl = file.VirtualPath
    };
  }

  /// Sort order among peer url resolvers.
  public int SortOrder {
    get;
    set;
  }
}

Query for a new context by URL

Context resolvers that implement the IUrlContextResolver interface are queried when you load a URL in the preview frame. Publish a message to programmatically change the context to the context associated with a URL, as shown in the following example.

// queries the context service for the context belonging to a URL
var contextParameters = { url: someUnknownUrl.toString() };
topic.publish("/epi/shell/context/request", [contextParameters, { sender: this }]);

ContextHistory and navigating back to the previous context

When an editor navigates from one context to another or the same, CMS keeps the history of every step through the ContextHistory and BackContextHistory classes on the client side (both are internal to Optimizely).

As a developer, you can clear the current context (and close the related view) and go back to the previous context. This is usually when you want to close or cancel a view related to the current context and go back.

For example, the project overview has a Close button. Clicking this button clears all project context history and returns to the previous context.

You can achieve the same thing with the contextNavigation object on the client side. This is a static object on the client side, exposing a method back. It clears the history of the current context and then goes to the previous context.

define("dojo/_base/declare", "epi-cms/contextNavigation", function (declare, contextNavigation) {
      return declare("epi.cms.component.MyCustomeView", {
          clicked: function () {
            contextNavigation.back(this);
          }
        }
      });