Glass Edit Frame – Immediately Invoking Wrapper

tl;dr; Custom HTML Helper to wrap Glass Edit Frame and JS code to immediately open the modal dialog for editing

As I’m sure most of you are aware, I 😍 Glass Mapper. So much so that I struggle with the native Sitecore API 😂 

Version 4 of the framework added an amazing feature which allows you to very simply and quickly create/bind to Edit Frames purely from code. Normally this is a bit of an annoying and long winded processing: switch over to the core database, create an item with names of the fields, serialize/sync to source control, do this for every combination of fields you have, hook it up to EditFrame code that until recently did not work in native Sitecore MVC 😆

I’m sure you’ve been using this feature, it’s super simple from code to add an EditFrame wherever you need and the best part is it’s bound against your strongly typed model:

@using (BeginEditFrame(Model.Page, "Edit Metadata", x => x.DisplayInMenu, x => x.Closed))
{
  <div>Let's add an Edit Frame around our rendering</div>
}

If you need to add another field then simply add it to the list of fields and Glass handles everything for you.

Due to the simplicity, we use these a lot. It’s the only way to edit certain types of fields in the Experience Editor (such as multilist fields, checkboxes, treelists etc) without using Rendering Parameters, which in itself would cause other issues such as not being able to personalise, sharing them in Final Layout renderings, translate them or put them through workflow.

Our frontend team did an amazing job to create some custom buttons for the Edit Frames, using FontAwesome to provide some iconography. We just add code like so wherever we need to add in a EditFrame:

@if (Sitecore.Context.PageMode.IsExperienceEditor)
{
  <div class="widget__properties">
    @using (Html.Glass().BeginEditFrame(Model, "Edit Properties", x => x.CssClass, x => x.BackgroundImage))
    {
      <p class="properties-button">Edit Properties</p>
    }
  </div>
}

This renders something like this:

Custom Edit Frame Wrapper

The problem is the code became a bit repetitive. We need something a bit simpler so we had consistent usage throughout the entire project without all the extra code bulk. I was also getting a bit annoyed by the pointless extra click of selecting the button then the cubes…

So here comes the code part. The end result is probably best demonstrated with a video:

You can see a static CodePen demo here: https://codepen.io/jammykam/pen/PKWRyz

What have we done? We’ve created an HTML Extension method which in turn wraps the Glass Edit Frame code. This allows us to carry out the PageMode check and add in our own wrapper markup. This also allows us to bind a custom JavaScript handler to the button to trigger the code which opens the Edit Frame modal.

<div class="scLooseFrameZone scEnabledChrome" sc_item="sitecore://master/{CC718A99-7B67-47E6-9138-65A08A95EC21}?lang=en&amp;ver=1" sc-part-of="editframe">
  <span class="scChromeData">
    {"commands":
     [{"click":"javascript:Sitecore.PageModes.PageEditor.postRequest('webedit:fieldeditor(command={86D83C17-F6CA-4B36-99BF-6965BCB72201},fields=Title|Description|Image,id={CC718A99-7B67-47E6-9138-65A08A95EC21})',null,false)",
        "header":"Edit Fields", "icon":"/temp/iconcache/people/16x16/cubes_blue.png",
        "disabledIcon":"/temp/cubes_blue_disabled16x16.png", "isDivider":false,
        "tooltip":"Edit the following fields: Title, Description, Image", "type":null}],
    "contextItemUri":"sitecore://master/{CC718A99-7B67-47E6-9138-65A08A95EC21}?lang=en&amp;ver=1",
    "custom":{},
    "displayName":" Edit Properties",
    "expandedDisplayName":""}
  </span>
  <button class="btn-editframe" title="Edit Properties">
    <i class="fa fa-edit"></i> Edit Properties
  </button>
</div>

We’re not doing anything magical, just immediately triggering the code that Sitecore would when you click the button from the webedit ribbon. The important line of code is hidden away in the scChromeData span and we just need to parse this and trigger the click command ourselves (line 4 above).

Usage

Include the JS and CSS files in Experience Editor mode and then use the HTML Helper to render the button style you require.

@Html.EditFrame(item, x => x.Link, x => x.Image) small button
small button
@Html.EditFrame(item, true, x => x.Link, x => x.Image) default text + button
default text + button
@Html.EditFrame(item, “fa-wrench”, x => x.Link, x => x.Image) small button, custom icon
small button, custom icon
@Html.EditFrame(item, “Override Text”, “”, x => x.Image) override text, default button
override text, default button
@Html.EditFrame(item, “Override Text”, “fa-cogs”, x => x.Setting) override text + button
override text + button
@Html.EditFrame(item, “Edit Background”, showTitle:false, “fa-image”, x => x.Image) ustom button, no text, set custom hover title
custom button, no text, set custom hover title

The buttons use FontAwesome Icons, you need to include a reference to the css file then you can pass in any valid class name to override the default: http://fontawesome.io/icons/
 
If you want to render multiple buttons then you need to use this IDisposable wrapper allowing you to group multiple buttons. This allows us to use some different styling so the buttons appear inline rather than stacking up on top of each other. It’s also possible to pass a CSS class to this wrapper if required (to set  different placement of the button, for example).

@using (Html.EditFrameWrapper())
{
  @Html.EditFrame(item, "fa-cogs", x => x.Setting)
  @Html.EditFrame(item, "fa-wrench", x => x.Configuration)
  @Html.EditFrame(item, "fa-image", x => x.Image)
}
Multiple Buttons

The above is all that you need. Nothing else. No using statements for single buttons. As you can see, really clean usage with the added benefit of allowing us to bind our custom JavaScript handler.

Code

Keep in mind that this is sample code that works for us. Our project uses Foundation 5 as a base, I’ve tried to extract out the styles so it should be framework agnostic. But, ya know, update the styles as required.

There’s not much to it but it took me a while to figure out all the pieces to make this work. I didn’t want to bog the post down with explanation of all the bits of the code, but guess why I wrote my last post about extending Sitecore JavaScript. Hopefully it makes sense but feel free to reach out to me or leave a comment.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s