🧩 Framework Components
Extending Cms Ui Gadgets
📖 Docs

Extending CMS UI - Gadgets, Menus, Views

Exam Area: Content Area 4 – Framework Components (15%)
Reference: https://docs.developers.optimizely.com/content-management-system/docs/user-interface


1. Gadgets

Gadgets are widgets that can be added to the Dashboard in the CMS.

Creating a Gadget:

// Gadget Controller
[EPiServer.Shell.Web.ScriptResource("ClientResources/Scripts/MyGadget.js")]
public class MyGadgetController : Controller
{
    public ActionResult Index()
    {
        var model = new MyGadgetViewModel
        {
            Title = "My Gadget",
            Count = GetItemCount()
        };
        return PartialView(model);
    }
}
<!-- module.config -->
<module>
  <guiPlugins>
    <add name="MyGadget"
         displayName="My Custom Gadget"
         description="Shows something useful"
         category="My Company"
         plugInArea="Dashboard"
         controlUrl="~/MyGadget/"
         sortIndex="100" />
  </guiPlugins>
</module>

2. Plugging in a Gadget

// Use an attribute to register a gadget
[GadgetWidgetPlugin(
    DisplayName = "Recent Changes",
    Description = "Shows recent content changes",
    WidgetUrl = "~/episerver/cms/gadgets/RecentChanges",
    PlugInAreas = PlugInArea.Dashboard)]
public class RecentChangesGadget { }

3. Adding Menu Items

// Add a menu item to CMS navigation
using EPiServer.Shell.Navigation;

[MenuItem("/global/cms/myitem",
    Text = "My Feature",
    TextResourceKey = "/mysite/menu/myfeature",
    Url = "~/episerver/cms/myfeature/",
    SortIndex = 200)]
public class MyMenuProvider { }

4. Menu Provider

// Custom menu provider (CMS 12 approach)
[MenuProvider]
public class MyMenuProvider : IMenuProvider
{
    public IEnumerable<MenuItem> GetMenuItems()
    {
        yield return new UrlMenuItem("My Feature", 
            "/global/cms/myfeature",
            "~/episerver/cms/myfeature/")
        {
            IsAvailable = context => context.RequestContext
                .HttpContext.User.IsInRole("WebAdmins"),
            SortIndex = 200,
            AuthorizationPolicy = "Authenticated"
        };
    }
}

5. Views (CMS Views)

// Create a custom view
[ViewConfiguration(
    Name = "MyView",
    ControllerType = typeof(MyViewController),
    ViewType = typeof(MyViewType),
    HideViewFromUI = false,
    IconClass = "epi-icon__layout")]
public class MyViewConfiguration : ViewConfiguration<MyViewType>
{
    public MyViewConfiguration()
    {
        Name = "MyView";
        Description = "My custom view";
        ContextualizationClass = "MyViewContextualizer";
    }
}

6. Plug-in Areas

// Available plug-in areas
PlugInArea.Dashboard       // Dashboard gadgets
PlugInArea.Navigation      // Navigation menu
PlugInArea.AssetsPanel     // Assets panel
PlugInArea.EditPanel       // Edit panel

7. TinyMCE Customization

// Configure TinyMCE
[InitializableModule]
public class TinyMceConfigModule : IInitializableModule
{
    public void Initialize(InitializationEngine context)
    {
        context.InitComplete += InitComplete;
    }

    private void InitComplete(object sender, InitializationEventArgs e)
    {
        var options = ServiceLocator.Current.GetInstance<TinyMceConfiguration>();
        
        // Add a custom plugin
        options.ForAll().AddPlugin("myplugin", "~/ClientResources/tinymce/myplugin.js");
        
        // Add a toolbar button
        options.ForAll().AppendToolbarRow("myplugin");
        
        // Style formats
        options.ForAll().AddStyleFormat(new StyleFormat
        {
            Name = "Custom Quote",
            Inline = "span",
            Classes = "custom-quote"
        });
    }

    public void Uninitialize(InitializationEngine context) { }
}

Configuration via appsettings.json:

{
  "EPiServer": {
    "TinyMce": {
      "Default": {
        "toolbar": "bold italic | link | code",
        "plugins": "lists link code"
      }
    }
  }
}

8. Custom Style Formats in TinyMCE

// Add CSS class options to TinyMCE
options.ForAll().AddStyleFormats(new[]
{
    new StyleFormat { Name = "Callout", Inline = "span", Classes = "callout" },
    new StyleFormat { Name = "Warning", Inline = "span", Classes = "warning" },
    new StyleFormat { Name = "Success Block", Block = "div", Classes = "success" }
});

9. Context-Sensitive Components

// A component displayed only in a specific context
[Component(
    PlugInAreas = new[] { "ContextualInformation" },
    SortIndex = 100)]
public class MyContextComponent : IComponent
{
    public string Name => "MyContextInfo";
    public string Categories => "cms";
}

10. Configuring Dashboard

// Add default gadgets to the dashboard
[InitializableModule]
public class DashboardConfig : IInitializableModule
{
    public void Initialize(InitializationEngine context)
    {
        // Configure default dashboard gadgets
    }
}

Review Questions

  1. In which area are gadgets placed? (PlugInArea.Dashboard)
  2. How do you add a menu item? ([MenuItem] attribute or IMenuProvider)
  3. Where is TinyMCE customization configured? (TinyMceConfiguration in an init module or appsettings.json)
  4. What is the [MenuProvider] attribute used for? (Registers a custom menu provider)
  5. What is ViewConfiguration used for? (Creating custom views in the Edit View)